@meshioplusplus/wasm 11.0.0 → 12.0.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/README.md +1 -1
- package/dist/meshioplusplus_wasm.mjs +1 -1
- package/dist/meshioplusplus_wasm.wasm +0 -0
- package/dist/meshioplusplus_wasm_mt.mjs +1 -1
- package/dist/meshioplusplus_wasm_mt.wasm +0 -0
- package/index.d.ts +487 -53
- package/package.json +2 -2
- package/src/index.mjs +338 -48
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshioplusplus/wasm",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "meshio++ mesh I/O compiled to WebAssembly: read
|
|
3
|
+
"version": "12.0.0",
|
|
4
|
+
"description": "meshio++ mesh I/O compiled to WebAssembly: read 43 and write 46 mesh formats (incl. MED, CGNS, Exodus) in the browser or Node.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.mjs",
|
|
7
7
|
"module": "./src/index.mjs",
|
package/src/index.mjs
CHANGED
|
@@ -30,6 +30,24 @@
|
|
|
30
30
|
// bundlers (Vite) emit both chunks. Callers can force a build with the
|
|
31
31
|
// `{ variant }` option.
|
|
32
32
|
|
|
33
|
+
// The raw xdmfSeriesWriteDataArrays embind call still converts every value
|
|
34
|
+
// with emscripten::convertJSArrayToNumberVector<double>, which throws on a
|
|
35
|
+
// BigInt64Array/BigUint64Array element (a JS `bigint` does not implicitly
|
|
36
|
+
// convert to `double`). Since data arrays now carry their source dtype
|
|
37
|
+
// (point_data/cell_data read off a mesh may be BigInt-backed), widen those to
|
|
38
|
+
// plain Float64-representable arrays here rather than in every caller.
|
|
39
|
+
function toDoubleConvertible(rArr) {
|
|
40
|
+
return rArr instanceof BigInt64Array || rArr instanceof BigUint64Array
|
|
41
|
+
? Array.from(rArr, Number)
|
|
42
|
+
: rArr;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function widenBigIntArrays(rObj) {
|
|
46
|
+
const out = {};
|
|
47
|
+
for (const [name, arr] of Object.entries(rObj)) out[name] = toDoubleConvertible(arr);
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
|
|
33
51
|
/**
|
|
34
52
|
* Decide which native artifact to load.
|
|
35
53
|
* @param {'auto'|'mt'|'seq'} variant
|
|
@@ -43,6 +61,35 @@ function resolveVariant(variant) {
|
|
|
43
61
|
return crossOriginIsolated ? 'mt' : 'seq';
|
|
44
62
|
}
|
|
45
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Thrown by `loadMeshioPlusPlus()` when a WASM module fails to instantiate,
|
|
66
|
+
* so a caller can tell a wrong `.wasm` URL from an environment that cannot
|
|
67
|
+
* run Wasm threads from a plain network failure, instead of catching a bare
|
|
68
|
+
* Emscripten abort. See doc/wasm.md's "Loading" section.
|
|
69
|
+
*/
|
|
70
|
+
export class MeshioPlusPlusLoadError extends Error {
|
|
71
|
+
/**
|
|
72
|
+
* @param {string} message
|
|
73
|
+
* @param {object} details
|
|
74
|
+
* @param {'mt'|'seq'} details.variant - which artifact was being loaded.
|
|
75
|
+
* @param {string} details.glue - the glue module specifier (e.g.
|
|
76
|
+
* '../dist/meshioplusplus_wasm_mt.mjs').
|
|
77
|
+
* @param {string} [details.requestedFile] - the filename Emscripten asked
|
|
78
|
+
* `locateFile` to resolve, if it got that far.
|
|
79
|
+
* @param {string} [details.resolvedUrl] - what `locateFile` returned for it.
|
|
80
|
+
* @param {unknown} [details.cause] - the underlying error/abort reason.
|
|
81
|
+
*/
|
|
82
|
+
constructor(message, { variant, glue, requestedFile, resolvedUrl, cause }) {
|
|
83
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
84
|
+
this.name = 'MeshioPlusPlusLoadError';
|
|
85
|
+
this.variant = variant;
|
|
86
|
+
this.glue = glue;
|
|
87
|
+
this.requestedFile = requestedFile;
|
|
88
|
+
this.resolvedUrl = resolvedUrl;
|
|
89
|
+
this.cause = cause;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
46
93
|
/**
|
|
47
94
|
* A rectangular (uniform node count) group of cells.
|
|
48
95
|
* @typedef {Object} RectangularCellBlock
|
|
@@ -90,27 +137,60 @@ function resolveVariant(variant) {
|
|
|
90
137
|
* @property {() => void} close - finalize (if needed) and release the handle.
|
|
91
138
|
*/
|
|
92
139
|
|
|
140
|
+
/**
|
|
141
|
+
* A single sequence entry: one step of one file. See {@link SequenceReader}.
|
|
142
|
+
* @typedef {Object} SequenceEntry
|
|
143
|
+
* @property {string} path
|
|
144
|
+
* @property {number} step
|
|
145
|
+
* @property {number} time
|
|
146
|
+
* @property {'explicit'|'file'|'filename'|'index'} timeSource
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @typedef {Object} SequenceReader
|
|
151
|
+
* @property {number} count
|
|
152
|
+
* @property {(i: number) => string} path
|
|
153
|
+
* @property {(i: number) => number} step
|
|
154
|
+
* @property {(i: number) => number} time
|
|
155
|
+
* @property {(i: number) => ('explicit'|'file'|'filename'|'index')} timeSource
|
|
156
|
+
* @property {(i: number) => SequenceEntry} entry
|
|
157
|
+
* @property {() => SequenceEntry[]} entries
|
|
158
|
+
* @property {(i: number, options?: {pointsOnly?: boolean, arrays?: string[]|null, lenient?: boolean}) => Mesh} read
|
|
159
|
+
* @property {() => void} close - release the handle; safe to call twice.
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* A point_data/cell_data/field_data array's JS type: it carries its source
|
|
164
|
+
* dtype crossing the WASM boundary rather than always widening to
|
|
165
|
+
* Float64Array (dtype carry, v11.2.0).
|
|
166
|
+
* @typedef {Float32Array|Float64Array|Int8Array|Int16Array|Int32Array|BigInt64Array|Uint8Array|Uint16Array|Uint32Array|BigUint64Array} DataArray
|
|
167
|
+
*/
|
|
168
|
+
|
|
93
169
|
/**
|
|
94
170
|
* @typedef {Object} Mesh
|
|
95
171
|
* @property {Float64Array} points - flat, row-major (numPoints * dim).
|
|
96
172
|
* @property {number} dim - 2 or 3.
|
|
97
173
|
* @property {CellBlock[]} cells
|
|
98
|
-
* @property {Object<string,
|
|
174
|
+
* @property {Object<string, DataArray>} [point_data]
|
|
99
175
|
* @property {Object<string, number>} [point_data_components] - per-entity width of any non-scalar point_data array, since a flat typed array carries no shape; absent name = 1 component.
|
|
100
|
-
* @property {Object<string,
|
|
176
|
+
* @property {Object<string, DataArray[]>} [cell_data] - one array per cell block, same order as `cells`; every block of one named array shares the same DataArray class.
|
|
101
177
|
* @property {Object<string, number>} [cell_data_components] - per-entity width of any non-scalar cell_data array (one value per array, not per block).
|
|
102
|
-
* @property {Object<string,
|
|
178
|
+
* @property {Object<string, DataArray>} [field_data]
|
|
103
179
|
* @property {Object<string, number>} [field_data_components] - per-entity width of any non-scalar field_data array.
|
|
180
|
+
* @property {Array<{name: string, kind: string, dim: number, tag: number, entries: Int32Array}>} [regions] - named point/cell/side groups, see doc/regions.md.
|
|
181
|
+
* @property {Array<{id: number, values: Array<{key: string, values: Float64Array, text: string, isTable: boolean, components?: number}>}>} [propertySets] - `Begin Properties` blocks (currently MDPA only), see doc/wasm.md.
|
|
104
182
|
*/
|
|
105
183
|
|
|
106
184
|
/**
|
|
107
185
|
* Instantiate a fresh meshio++ WASM module.
|
|
108
186
|
*
|
|
109
187
|
* @param {object} [moduleOverrides] - forwarded to the Emscripten module
|
|
110
|
-
* factory
|
|
111
|
-
*
|
|
112
|
-
* `locateFile
|
|
113
|
-
*
|
|
188
|
+
* factory (with `locateFile`/`onAbort` wrapped for diagnostics -- see
|
|
189
|
+
* {@link MeshioPlusPlusLoadError} -- your own overrides still run first).
|
|
190
|
+
* `{ locateFile: (p) => new URL(p, import.meta.url) }` relocates the
|
|
191
|
+
* `.wasm` binary for a bundler/CDN setup; `locateFile` receives the
|
|
192
|
+
* requested filename, so return the URL matching the loaded variant
|
|
193
|
+
* (`meshioplusplus_wasm.wasm` or `_wasm_mt.wasm`).
|
|
114
194
|
* @param {object} [options]
|
|
115
195
|
* @param {'auto'|'mt'|'seq'} [options.variant='auto'] - which native artifact to
|
|
116
196
|
* load. `auto` picks the threaded (`mt`) build under Node and in a
|
|
@@ -119,11 +199,11 @@ function resolveVariant(variant) {
|
|
|
119
199
|
* @returns {Promise<{
|
|
120
200
|
* FS: object,
|
|
121
201
|
* readMesh: (path: string, format?: string) => Mesh,
|
|
122
|
-
* readMeshSelective: (path: string, options?: {format?: string, pointsOnly?: boolean, arrays?: string[], timeStep?: number, lenient?: boolean}) => Mesh,
|
|
202
|
+
* readMeshSelective: (path: string, options?: {format?: string, pointsOnly?: boolean, arrays?: string[], timeStep?: number, lenient?: boolean, info?: boolean}) => Mesh,
|
|
123
203
|
* readMetadata: (path: string, format?: string) => object,
|
|
124
204
|
* readerSupportsOptions: (format: string) => boolean,
|
|
125
|
-
* writeMesh: (path: string, mesh: Mesh, format?: string) =>
|
|
126
|
-
* convert: (inPath: string, outPath: string, options?: {inFormat?: string, outFormat?: string}) =>
|
|
205
|
+
* writeMesh: (path: string, mesh: Mesh, format?: string, options?: {encoding?: string, codec?: string, floatFormat?: string, info?: object}) => string[],
|
|
206
|
+
* convert: (inPath: string, outPath: string, options?: {inFormat?: string, outFormat?: string, encoding?: string, codec?: string, floatFormat?: string}) => string[],
|
|
127
207
|
* convertSurface: (inPath: string, outPath: string, options?: {inFormat?: string, outFormat?: string}) => void,
|
|
128
208
|
* convertSurfaceOps: (inPath: string, outPath: string, ops?: object[], options?: {inFormat?: string, outFormat?: string, keepProvenance?: boolean}) => {steps: object[], warnings: string[]},
|
|
129
209
|
* runPipeline: (settings: object|string) => {steps: object[], warnings: string[]},
|
|
@@ -144,13 +224,16 @@ function resolveVariant(variant) {
|
|
|
144
224
|
* computeBandwidth: (mesh: Mesh) => number,
|
|
145
225
|
* diff: (a: Mesh, b: Mesh, atol?: number, rtol?: number, unordered?: boolean) => object,
|
|
146
226
|
* meshesEqual: (a: Mesh, b: Mesh, atol?: number, rtol?: number, unordered?: boolean) => boolean,
|
|
147
|
-
* merge: (meshes: Mesh[], weld?: boolean, atol?: number, sourceTag?: boolean, dataPolicy?: string, dropDuplicateCells?: boolean) => Mesh,
|
|
227
|
+
* merge: (meshes: Mesh[], weld?: boolean, atol?: number, sourceTag?: boolean, dataPolicy?: string, dropDuplicateCells?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMaps: Int32Array[], cellMaps: Int32Array[]},
|
|
148
228
|
* transform: (mesh: Mesh, matrix: number[], rotateVectorData?: boolean) => Mesh,
|
|
149
|
-
* clean: (mesh: Mesh, weld?: boolean, atol?: number, removeOrphans?: boolean, dropDegenerate?: boolean, dropDuplicateCells?: boolean) => {mesh: Mesh, pointsWelded: number, pointsRemovedOrphan: number, cellsDroppedDegenerate: number, cellsDroppedDuplicate: number},
|
|
150
|
-
* smooth: (mesh: Mesh, method?: string, iterations?: number, lambda?: number, mu?: number, fixBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, guardInversion?: boolean) => {mesh: Mesh, numNodesMoved: number, maxDisplacement: number, numSkippedInversion: number},
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
229
|
+
* clean: (mesh: Mesh, weld?: boolean, atol?: number, removeOrphans?: boolean, dropDegenerate?: boolean, dropDuplicateCells?: boolean, returnMaps?: boolean) => {mesh: Mesh, pointsWelded: number, pointsRemovedOrphan: number, cellsDroppedDegenerate: number, cellsDroppedDuplicate: number, pointMap?: Int32Array, cellMaps?: Int32Array[]},
|
|
230
|
+
* smooth: (mesh: Mesh, method?: string, iterations?: number, lambda?: number, mu?: number, fixBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, guardInversion?: boolean, frozen?: number[]|Int32Array|null) => {mesh: Mesh, numNodesMoved: number, maxDisplacement: number, numSkippedInversion: number},
|
|
231
|
+
* interpolate: (source: Mesh, target: Mesh, method?: string, arrays?: string[], extrapolate?: boolean, defaultValue?: number, onConflict?: string) => Mesh,
|
|
232
|
+
* conservativeInterpolate: (source: Mesh, target: Mesh, arrays?: string[], defaultValue?: number, onConflict?: string) => Mesh,
|
|
233
|
+
* undoGreen: (coarse: Mesh, fine: Mesh) => {mesh: Mesh, numGroupsUndone: number, numCellsRemoved: number},
|
|
234
|
+
* cropBbox: (mesh: Mesh, lo: number[], hi: number[], mode?: string, recordIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
235
|
+
* cropPlane: (mesh: Mesh, point: number[], normal: number[], mode?: string, recordIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
236
|
+
* cropPredicate: (mesh: Mesh, array: string, compare?: string, value?: number, recordIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
154
237
|
* slice: (mesh: Mesh, origin: number[], normal: number[], recordParentIds?: boolean) => Mesh,
|
|
155
238
|
* isosurface: (mesh: Mesh, array: string, isovalues: number|number[], component?: number, recordParentIds?: boolean) => Mesh,
|
|
156
239
|
* grid: (dims: number[], origin?: number[], spacing?: number[], maxCells?: number) => Mesh,
|
|
@@ -169,13 +252,16 @@ function resolveVariant(variant) {
|
|
|
169
252
|
* repair: (mesh: Mesh, fixOrientation?: boolean, orientOutward?: boolean, fillHoles?: boolean, splitNonManifold?: boolean, maxHoleEdges?: number, weldTolerance?: number, recordProvenance?: boolean) => {mesh: Mesh, qualityBefore: object, qualityAfter: object, numFlipped: number, numComponents: number, largestComponent: number, numOrientedOutward: number, numUnorientable: number, numVerticesSplit: number, numHolesDetected: number, numHolesFilled: number, numHolesSkipped: number, numFacesAdded: number, numPointsAdded: number, pointsWelded: number},
|
|
170
253
|
* shrinkwrap: (mesh: Mesh, target: Mesh, offset?: number, maxDistance?: number, weights?: string, targetRegion?: string, normalWeight?: string, recordDistance?: boolean, recordClosestCell?: boolean) => {mesh: Mesh, quality: object, numProjected: number, numMissed: number, numSkipped: number, maxDisplacement: number},
|
|
171
254
|
* sobolevDeform: (mesh: Mesh, array: string, lengthScale: number, fixedPointsArray?: string, fixBoundary?: boolean, recordFiltered?: boolean, maxIterations?: number, tolerance?: number) => {mesh: Mesh, numIterations: number, residual: number, converged: boolean, numFixed: number, numIsolated: number, maxDisplacement: number},
|
|
172
|
-
* split: (mesh: Mesh, by: string, tagName?: string) => {key: string, mesh: Mesh}[],
|
|
173
|
-
* convertCells: (mesh: Mesh, mode?: string, recordParentIds?: boolean) => Mesh,
|
|
174
|
-
* subdivide: (mesh: Mesh, recordParentIds?: boolean) => Mesh,
|
|
175
|
-
* agglomerate: (mesh: Mesh, targetGroupSize?: number) => Mesh,
|
|
255
|
+
* split: (mesh: Mesh, by: string, tagName?: string, returnMaps?: boolean) => {key: string, mesh: Mesh, pointMap?: Int32Array, cellMaps?: Int32Array[]}[],
|
|
256
|
+
* convertCells: (mesh: Mesh, mode?: string, recordParentIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
257
|
+
* subdivide: (mesh: Mesh, recordParentIds?: boolean, returnMaps?: boolean) => Mesh | {mesh: Mesh, cellMaps: Int32Array[]},
|
|
258
|
+
* agglomerate: (mesh: Mesh, targetGroupSize?: number, returnMaps?: boolean) => Mesh | {mesh: Mesh, cellMap: Int32Array},
|
|
176
259
|
* refine: (mesh: Mesh, levels?: number, recordParentIds?: boolean,
|
|
177
|
-
* options?: object) => Mesh,
|
|
178
|
-
* decimate: (mesh: Mesh, ratio?: number, targetFaces?: number, maxError?: number, placement?: string, preserveBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number) => {mesh: Mesh, facesRemoved: number, pointsRemoved: number, collapsesRejected: number, maxErrorApplied: number},
|
|
260
|
+
* options?: object, returnMaps?: boolean) => Mesh | {mesh: Mesh, pointMap: Int32Array, cellMaps: Int32Array[]},
|
|
261
|
+
* decimate: (mesh: Mesh, ratio?: number, targetFaces?: number, maxError?: number, placement?: string, preserveBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, frozen?: number[]|Int32Array|null, returnMaps?: boolean) => {mesh: Mesh, facesRemoved: number, pointsRemoved: number, collapsesRejected: number, maxErrorApplied: number, pointMap?: Int32Array, cellMaps?: Int32Array[]},
|
|
262
|
+
* decimateVolume: (mesh: Mesh, ratio?: number, targetCells?: number, maxError?: number, placement?: string, preserveBoundary?: boolean, preserveFeatures?: boolean, featureAngle?: number, frozen?: number[]|Int32Array|null, returnMaps?: boolean) => {mesh: Mesh, tetsRemoved: number, pointsRemoved: number, collapsesRejected: number, maxErrorApplied: number, pointMap?: Int32Array, cellMaps?: Int32Array[]},
|
|
263
|
+
* partition: (mesh: Mesh, nparts: number, method?: string, imbalance?: number, mode?: string, seed?: number, recordIds?: boolean, ghostLayers?: number, weightsKey?: string, returnMaps?: boolean) => {partId: number, mesh: Mesh, pointMap?: Int32Array, cellMaps?: Int32Array[]}[],
|
|
264
|
+
* partitionLabels: (mesh: Mesh, nparts: number, method?: string, imbalance?: number, mode?: string, seed?: number, weightsKey?: string) => number[][],
|
|
179
265
|
* stats: (mesh: Mesh) => object,
|
|
180
266
|
* withProvenance: <T>(mode: number|null|undefined, fn: () => T) => T,
|
|
181
267
|
* provenanceBegin: (mode?: number) => void,
|
|
@@ -194,17 +280,75 @@ function resolveVariant(variant) {
|
|
|
194
280
|
* dataInfo: (mesh: Mesh) => object[],
|
|
195
281
|
* dataIntegrate: (mesh: Mesh, arrays?: string[]) => object[],
|
|
196
282
|
* createXdmfTimeSeriesWriter: (path: string, options?: {dataFormat?: string, gzipLevel?: number, mode?: 'truncate'|'append', autoFlush?: boolean}) => XdmfTimeSeriesWriter,
|
|
283
|
+
* openSequence: (source: string|string[], options?: object) => SequenceReader,
|
|
197
284
|
* }>}
|
|
285
|
+
* @throws {MeshioPlusPlusLoadError} if the WASM module fails to instantiate.
|
|
198
286
|
*/
|
|
199
287
|
export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto' } = {}) {
|
|
200
288
|
const chosen = resolveVariant(variant);
|
|
289
|
+
const glue =
|
|
290
|
+
chosen === 'mt' ? '../dist/meshioplusplus_wasm_mt.mjs' : '../dist/meshioplusplus_wasm.mjs';
|
|
201
291
|
// Literal specifiers so bundlers emit both chunks; the sequential one is
|
|
202
292
|
// the fallback whenever threads are unavailable.
|
|
203
293
|
const { default: createRawModule } =
|
|
204
294
|
chosen === 'mt'
|
|
205
295
|
? await import('../dist/meshioplusplus_wasm_mt.mjs')
|
|
206
296
|
: await import('../dist/meshioplusplus_wasm.mjs');
|
|
207
|
-
|
|
297
|
+
|
|
298
|
+
// Wrap locateFile/onAbort (rather than passing moduleOverrides through
|
|
299
|
+
// untouched) so a failed instantiation can be reported with which file
|
|
300
|
+
// Emscripten actually asked for and what locateFile resolved it to,
|
|
301
|
+
// instead of a bare Emscripten abort message. onAbort is overridden even
|
|
302
|
+
// though the try/catch below is the primary path, because an abort under
|
|
303
|
+
// Node does not always surface as a catchable rejection in every
|
|
304
|
+
// Emscripten build -- this guarantees the reason is captured regardless.
|
|
305
|
+
const userLocateFile = moduleOverrides.locateFile;
|
|
306
|
+
const userOnAbort = moduleOverrides.onAbort;
|
|
307
|
+
let requestedFile;
|
|
308
|
+
let resolvedUrl;
|
|
309
|
+
let abortReason;
|
|
310
|
+
const wrappedOverrides = {
|
|
311
|
+
...moduleOverrides,
|
|
312
|
+
locateFile: (path, prefix) => {
|
|
313
|
+
requestedFile = path;
|
|
314
|
+
resolvedUrl = userLocateFile ? userLocateFile(path, prefix) : prefix + path;
|
|
315
|
+
return resolvedUrl;
|
|
316
|
+
},
|
|
317
|
+
onAbort: (reason) => {
|
|
318
|
+
abortReason = reason;
|
|
319
|
+
if (userOnAbort) userOnAbort(reason);
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
let Module;
|
|
324
|
+
try {
|
|
325
|
+
Module = await createRawModule(wrappedOverrides);
|
|
326
|
+
} catch (cause) {
|
|
327
|
+
throw new MeshioPlusPlusLoadError(
|
|
328
|
+
`meshio++ (wasm): failed to instantiate the '${chosen}' variant (${glue}): ` +
|
|
329
|
+
`${abortReason ?? cause.message ?? cause}. Emscripten requested ` +
|
|
330
|
+
`'${requestedFile}' and locateFile returned '${resolvedUrl}'.`,
|
|
331
|
+
{ variant: chosen, glue, requestedFile, resolvedUrl, cause },
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// A mismatched locateFile (e.g. the seq .wasm handed to the mt glue) does
|
|
336
|
+
// not always fail instantiation with a LinkError -- the two binaries share
|
|
337
|
+
// enough of an export surface that it can link and then silently behave
|
|
338
|
+
// like the wrong variant. parallelBackend() is the cheap, always-present
|
|
339
|
+
// tell: catch it here rather than let every caller re-discover it.
|
|
340
|
+
const expectedBackend = chosen === 'mt' ? 'openmp' : 'seq';
|
|
341
|
+
const actualBackend = Module.parallelBackend();
|
|
342
|
+
if (actualBackend !== expectedBackend) {
|
|
343
|
+
throw new MeshioPlusPlusLoadError(
|
|
344
|
+
`meshio++ (wasm): failed to instantiate the '${chosen}' variant (${glue}): ` +
|
|
345
|
+
`loaded, but reports parallel backend '${actualBackend}' (expected ` +
|
|
346
|
+
`'${expectedBackend}') -- locateFile likely returned the wrong .wasm binary. ` +
|
|
347
|
+
`Emscripten requested '${requestedFile}' and locateFile returned '${resolvedUrl}'.`,
|
|
348
|
+
{ variant: chosen, glue, requestedFile, resolvedUrl },
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
208
352
|
return {
|
|
209
353
|
FS: Module.FS,
|
|
210
354
|
readMesh: (path, format = '') => Module.readMesh(path, format),
|
|
@@ -216,6 +360,11 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
216
360
|
// first, negative counts from the end, out of range throws.
|
|
217
361
|
// `lenient` downgrades "this reader cannot represent construct X" to a
|
|
218
362
|
// warning plus a skip; a malformed file still throws.
|
|
363
|
+
// `info: true` attaches the format's side channel as `mesh.info`
|
|
364
|
+
// (openfoam/med/mdpa/ansysinp/unv/gmsh/exodus; ignored, not thrown,
|
|
365
|
+
// for any other format) -- see doc/wasm.md's "Side channel (info)"
|
|
366
|
+
// section. `pointsOnly`/`arrays` reach it only for the formats whose
|
|
367
|
+
// info reader takes selective-read options (med/mdpa/gmsh/exodus).
|
|
219
368
|
readMeshSelective: (
|
|
220
369
|
path,
|
|
221
370
|
{
|
|
@@ -224,15 +373,37 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
224
373
|
arrays = null,
|
|
225
374
|
timeStep = 0,
|
|
226
375
|
lenient = false,
|
|
376
|
+
info = false,
|
|
227
377
|
} = {},
|
|
228
|
-
) => Module.readMeshSelective(path, format, pointsOnly, arrays, timeStep, lenient),
|
|
378
|
+
) => Module.readMeshSelective(path, format, pointsOnly, arrays, timeStep, lenient, info),
|
|
229
379
|
// Summarize a file without loading its heavy arrays. The returned
|
|
230
380
|
// object's `fellBackToFullRead` says whether that was actually cheap.
|
|
231
381
|
readMetadata: (path, format = '') => Module.readMetadata(path, format),
|
|
232
382
|
readerSupportsOptions: (format) => Module.readerSupportsOptions(format),
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
383
|
+
// `options`: `{encoding, codec, floatFormat, info}`, all optional --
|
|
384
|
+
// unset/empty reproduces the exact pre-v11.2.0 write. `encoding` is
|
|
385
|
+
// 'ascii'/'binary' (format-default otherwise); `codec` is a VTK-XML
|
|
386
|
+
// (vtu/vtp) block-compression codec, 'none'/'zlib'/'lz4'/'zstd'; an
|
|
387
|
+
// option a format cannot honour throws naming the format. `info`
|
|
388
|
+
// writes that format's side channel (openfoam/mdpa/ansysinp/unv/gmsh/
|
|
389
|
+
// med); when omitted, `mesh.info` is used instead if its own
|
|
390
|
+
// `format` matches this write's -- a read(info:true) round-trips
|
|
391
|
+
// back through a write with no extra plumbing. `info` given for a
|
|
392
|
+
// format with no side-channel writer (e.g. exodus, read-only, or any
|
|
393
|
+
// format without one at all) throws naming it. Returns every
|
|
394
|
+
// virtual-FS path the write touched (new or changed), sorted -- more
|
|
395
|
+
// than one for a multi-file writer (`.xdmf` + its `.h5` companion,
|
|
396
|
+
// an OpenFOAM `polyMesh` directory's files, ...).
|
|
397
|
+
writeMesh: (path, mesh, format = '', options = undefined) =>
|
|
398
|
+
Module.writeMesh(path, mesh, format, options),
|
|
399
|
+
// `options` adds `encoding`/`codec`/`floatFormat` to `inFormat`/
|
|
400
|
+
// `outFormat` (see `writeMesh`). Returns the written paths, as
|
|
401
|
+
// `writeMesh` does.
|
|
402
|
+
convert: (
|
|
403
|
+
inPath,
|
|
404
|
+
outPath,
|
|
405
|
+
{ inFormat = '', outFormat = '', encoding, codec, floatFormat } = {},
|
|
406
|
+
) => Module.convert(inPath, inFormat, outPath, outFormat, { encoding, codec, floatFormat }),
|
|
236
407
|
// Like `convert`, but writes a renderable *surface*: a volume mesh
|
|
237
408
|
// becomes its boundary, everything else passes through, and the result
|
|
238
409
|
// is linearized. Prefer this over readMesh -> extractSkin -> writeMesh
|
|
@@ -307,6 +478,9 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
307
478
|
Module.diff(a, b, atol, rtol, unordered),
|
|
308
479
|
meshesEqual: (a, b, atol = 0, rtol = 0, unordered = false) =>
|
|
309
480
|
Module.meshesEqual(a, b, atol, rtol, unordered),
|
|
481
|
+
// `returnMaps` (default false): when true, returns
|
|
482
|
+
// `{mesh, pointMaps, cellMaps}` instead of a bare mesh -- one array
|
|
483
|
+
// per input mesh, in input order.
|
|
310
484
|
merge: (
|
|
311
485
|
meshes,
|
|
312
486
|
weld = false,
|
|
@@ -314,9 +488,15 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
314
488
|
sourceTag = true,
|
|
315
489
|
dataPolicy = 'intersection',
|
|
316
490
|
dropDuplicateCells = false,
|
|
317
|
-
|
|
491
|
+
returnMaps = false,
|
|
492
|
+
) =>
|
|
493
|
+
Module.merge(
|
|
494
|
+
meshes, weld, atol, sourceTag, dataPolicy, dropDuplicateCells, returnMaps,
|
|
495
|
+
),
|
|
318
496
|
transform: (mesh, matrix, rotateVectorData = false) =>
|
|
319
497
|
Module.transform(mesh, matrix, rotateVectorData),
|
|
498
|
+
// `returnMaps` (default false): when true, the result also carries
|
|
499
|
+
// `pointMap`/`cellMaps` (input index -> output index, -1 if dropped).
|
|
320
500
|
clean: (
|
|
321
501
|
mesh,
|
|
322
502
|
weld = false,
|
|
@@ -324,10 +504,16 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
324
504
|
removeOrphans = true,
|
|
325
505
|
dropDegenerate = true,
|
|
326
506
|
dropDuplicateCells = true,
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
507
|
+
returnMaps = false,
|
|
508
|
+
) =>
|
|
509
|
+
Module.clean(
|
|
510
|
+
mesh, weld, atol, removeOrphans, dropDegenerate, dropDuplicateCells, returnMaps,
|
|
511
|
+
),
|
|
512
|
+
// `method` is 'taubin', 'laplacian' or 'odt' (tet-only). A negative
|
|
513
|
+
// `lambda` means "this method's own default" (0.5 Laplacian, 0.33
|
|
514
|
+
// Taubin) and is forwarded unchanged. `frozen` is an optional array of
|
|
515
|
+
// 0-based point ids to pin outright, unioned with any boundary/feature
|
|
516
|
+
// pins; an out-of-range id throws by name.
|
|
331
517
|
smooth: (
|
|
332
518
|
mesh,
|
|
333
519
|
method = 'taubin',
|
|
@@ -338,6 +524,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
338
524
|
preserveFeatures = true,
|
|
339
525
|
featureAngle = 30,
|
|
340
526
|
guardInversion = true,
|
|
527
|
+
frozen = null,
|
|
341
528
|
) =>
|
|
342
529
|
Module.smooth(
|
|
343
530
|
mesh,
|
|
@@ -349,6 +536,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
349
536
|
preserveFeatures,
|
|
350
537
|
featureAngle,
|
|
351
538
|
guardInversion,
|
|
539
|
+
frozen,
|
|
352
540
|
),
|
|
353
541
|
// Cross-mesh field transfer: source point_data sampled at the target's
|
|
354
542
|
// points, source cell_data by nearest source-cell centroid regardless
|
|
@@ -391,12 +579,15 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
391
579
|
// Restore `fine`'s transitional (green) cells to their coarse parent,
|
|
392
580
|
// read verbatim from `coarse` (a lookup, not a reconstruction).
|
|
393
581
|
undoGreen: (coarse, fine) => Module.undoGreen(coarse, fine),
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
Module.
|
|
398
|
-
|
|
399
|
-
Module.
|
|
582
|
+
// Each crop* returns a bare mesh, or `{mesh, pointMap, cellMaps}` when
|
|
583
|
+
// `returnMaps` (the trailing argument, default false) is set.
|
|
584
|
+
cropBbox: (mesh, lo, hi, mode = 'all', recordIds = false, returnMaps = false) =>
|
|
585
|
+
Module.cropBbox(mesh, lo, hi, mode, recordIds, returnMaps),
|
|
586
|
+
cropPlane: (mesh, point, normal, mode = 'all', recordIds = false, returnMaps = false) =>
|
|
587
|
+
Module.cropPlane(mesh, point, normal, mode, recordIds, returnMaps),
|
|
588
|
+
cropPredicate: (
|
|
589
|
+
mesh, array, compare = '<', value = 0, recordIds = false, returnMaps = false,
|
|
590
|
+
) => Module.cropPredicate(mesh, array, compare, value, recordIds, returnMaps),
|
|
400
591
|
slice: (mesh, origin, normal, recordParentIds = false) =>
|
|
401
592
|
Module.slice(mesh, origin, normal, recordParentIds),
|
|
402
593
|
grid: (dims, origin = null, spacing = null, maxCells = 20000000) =>
|
|
@@ -598,15 +789,33 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
598
789
|
) =>
|
|
599
790
|
Module.sobolevDeform(mesh, array, lengthScale, fixedPointsArray, fixBoundary,
|
|
600
791
|
recordFiltered, maxIterations, tolerance),
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
//
|
|
792
|
+
// `returnMaps` (default false): when true, each `{key, mesh}` piece
|
|
793
|
+
// also carries `pointMap`/`cellMaps`.
|
|
794
|
+
split: (mesh, by, tagName = '', returnMaps = false) =>
|
|
795
|
+
Module.split(mesh, by, tagName, returnMaps),
|
|
796
|
+
// `returnMaps` (default false): when true, returns
|
|
797
|
+
// `{mesh, pointMap, cellMaps}` instead of a bare mesh.
|
|
798
|
+
convertCells: (mesh, mode = 'linearize', recordParentIds = false, returnMaps = false) =>
|
|
799
|
+
Module.convertCells(mesh, mode, recordParentIds, returnMaps),
|
|
800
|
+
// `returnMaps` (default false): when true, returns `{mesh, cellMaps}`
|
|
801
|
+
// instead of a bare mesh -- there is no point map (subdivide never
|
|
802
|
+
// prunes or renumbers a point).
|
|
803
|
+
subdivide: (mesh, recordParentIds = false, returnMaps = false) =>
|
|
804
|
+
Module.subdivide(mesh, recordParentIds, returnMaps),
|
|
805
|
+
// `returnMaps` (default false): when true, returns `{mesh, cellMap}`
|
|
806
|
+
// instead of a bare mesh -- a single FLAT array (global cell index ->
|
|
807
|
+
// global cell index), unlike the other ops' per-block `cellMaps`.
|
|
808
|
+
agglomerate: (mesh, targetGroupSize = 8, returnMaps = false) =>
|
|
809
|
+
Module.agglomerate(mesh, targetGroupSize, returnMaps),
|
|
810
|
+
// `returnMaps` (default false): when true, returns
|
|
811
|
+
// `{mesh, pointMap, cellMaps}` instead of a bare mesh.
|
|
812
|
+
refine: (mesh, levels = 1, recordParentIds = false, options = undefined,
|
|
813
|
+
returnMaps = false) =>
|
|
814
|
+
Module.refine(mesh, levels, recordParentIds, options, returnMaps),
|
|
815
|
+
// Exactly one of ratio / targetFaces / maxError must be non-negative.
|
|
816
|
+
// `frozen` is an optional array of 0-based point ids to pin outright;
|
|
817
|
+
// an out-of-range id throws by name. `returnMaps` (default false):
|
|
818
|
+
// when true, the result also carries `pointMap`/`cellMaps`.
|
|
610
819
|
decimate: (
|
|
611
820
|
mesh,
|
|
612
821
|
ratio = -1,
|
|
@@ -616,6 +825,8 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
616
825
|
preserveBoundary = true,
|
|
617
826
|
preserveFeatures = true,
|
|
618
827
|
featureAngle = 30,
|
|
828
|
+
frozen = null,
|
|
829
|
+
returnMaps = false,
|
|
619
830
|
) =>
|
|
620
831
|
Module.decimate(
|
|
621
832
|
mesh,
|
|
@@ -626,7 +837,42 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
626
837
|
preserveBoundary,
|
|
627
838
|
preserveFeatures,
|
|
628
839
|
featureAngle,
|
|
840
|
+
frozen,
|
|
841
|
+
returnMaps,
|
|
842
|
+
),
|
|
843
|
+
// Tetrahedral VOLUME decimation (decimate's tet-edge-collapse sibling).
|
|
844
|
+
// Exactly one of ratio / targetCells / maxError must be non-negative.
|
|
845
|
+
// `preserveBoundary` defaults to false here, matching the C++ default
|
|
846
|
+
// (decimate's own default is true) -- decimateVolume's boundary is
|
|
847
|
+
// usually interior geometry a solver still wants simplified.
|
|
848
|
+
// `returnMaps` (default false): when true, the result also carries
|
|
849
|
+
// `pointMap`/`cellMaps`.
|
|
850
|
+
decimateVolume: (
|
|
851
|
+
mesh,
|
|
852
|
+
ratio = -1,
|
|
853
|
+
targetCells = -1,
|
|
854
|
+
maxError = -1,
|
|
855
|
+
placement = 'optimal',
|
|
856
|
+
preserveBoundary = false,
|
|
857
|
+
preserveFeatures = true,
|
|
858
|
+
featureAngle = 30,
|
|
859
|
+
frozen = null,
|
|
860
|
+
returnMaps = false,
|
|
861
|
+
) =>
|
|
862
|
+
Module.decimateVolume(
|
|
863
|
+
mesh,
|
|
864
|
+
ratio,
|
|
865
|
+
targetCells,
|
|
866
|
+
maxError,
|
|
867
|
+
placement,
|
|
868
|
+
preserveBoundary,
|
|
869
|
+
preserveFeatures,
|
|
870
|
+
featureAngle,
|
|
871
|
+
frozen,
|
|
872
|
+
returnMaps,
|
|
629
873
|
),
|
|
874
|
+
// `returnMaps` (default false): when true, each `{partId, mesh}`
|
|
875
|
+
// piece also carries `pointMap`/`cellMaps`.
|
|
630
876
|
partition: (
|
|
631
877
|
mesh,
|
|
632
878
|
nparts,
|
|
@@ -637,6 +883,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
637
883
|
recordIds = false,
|
|
638
884
|
ghostLayers = 0,
|
|
639
885
|
weightsKey = '',
|
|
886
|
+
returnMaps = false,
|
|
640
887
|
) =>
|
|
641
888
|
Module.partition(
|
|
642
889
|
mesh,
|
|
@@ -648,6 +895,7 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
648
895
|
recordIds,
|
|
649
896
|
ghostLayers,
|
|
650
897
|
weightsKey,
|
|
898
|
+
returnMaps,
|
|
651
899
|
),
|
|
652
900
|
partitionLabels: (
|
|
653
901
|
mesh,
|
|
@@ -733,7 +981,13 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
733
981
|
// Raw solver arrays instead of a mesh; `components` gives the
|
|
734
982
|
// per-entity width of any array that is not a scalar.
|
|
735
983
|
writeDataArrays: (time, pointData, cellData = {}, components = {}) =>
|
|
736
|
-
Module.xdmfSeriesWriteDataArrays(
|
|
984
|
+
Module.xdmfSeriesWriteDataArrays(
|
|
985
|
+
handle,
|
|
986
|
+
time,
|
|
987
|
+
widenBigIntArrays(pointData),
|
|
988
|
+
widenBigIntArrays(cellData),
|
|
989
|
+
components,
|
|
990
|
+
),
|
|
737
991
|
// Make the `.xdmf` readable now, without finalizing.
|
|
738
992
|
flush: () => Module.xdmfSeriesFlush(handle),
|
|
739
993
|
finalize: () => Module.xdmfSeriesFinalize(handle),
|
|
@@ -753,6 +1007,42 @@ export async function loadMeshioPlusPlus(moduleOverrides = {}, { variant = 'auto
|
|
|
753
1007
|
},
|
|
754
1008
|
};
|
|
755
1009
|
},
|
|
1010
|
+
// Stateful sequence reader (see doc/sequences.md) -- the other
|
|
1011
|
+
// stateful thing in this API, the same opaque-handle-plus-free-
|
|
1012
|
+
// functions shape as createXdmfTimeSeriesWriter above. `source`/
|
|
1013
|
+
// `options` are exactly sequenceEntries'; this plans the sequence
|
|
1014
|
+
// once (`entries()`) and lets a caller read one step at a time
|
|
1015
|
+
// (`read()`) without holding more than one mesh alive, unlike
|
|
1016
|
+
// sequenceEntries + readMesh in a loop, which still requires the
|
|
1017
|
+
// caller to resolve the format/step itself.
|
|
1018
|
+
openSequence: (source, options = undefined) => {
|
|
1019
|
+
const handle = Module.sequenceOpen(source, options);
|
|
1020
|
+
const count = Module.sequenceCount(handle);
|
|
1021
|
+
const entry = (i) => ({
|
|
1022
|
+
path: Module.sequencePath(handle, i),
|
|
1023
|
+
step: Module.sequenceStep(handle, i),
|
|
1024
|
+
time: Module.sequenceTime(handle, i),
|
|
1025
|
+
timeSource: Module.sequenceTimeSource(handle, i),
|
|
1026
|
+
});
|
|
1027
|
+
let open = true;
|
|
1028
|
+
return {
|
|
1029
|
+
count,
|
|
1030
|
+
path: (i) => Module.sequencePath(handle, i),
|
|
1031
|
+
step: (i) => Module.sequenceStep(handle, i),
|
|
1032
|
+
time: (i) => Module.sequenceTime(handle, i),
|
|
1033
|
+
timeSource: (i) => Module.sequenceTimeSource(handle, i),
|
|
1034
|
+
entry,
|
|
1035
|
+
entries: () => Array.from({ length: count }, (_, i) => entry(i)),
|
|
1036
|
+
read: (i, { pointsOnly = false, arrays = null, lenient = false } = {}) =>
|
|
1037
|
+
Module.sequenceRead(handle, i, { pointsOnly, arrays, lenient }),
|
|
1038
|
+
// Safe to call twice; safe to call in a `finally`.
|
|
1039
|
+
close: () => {
|
|
1040
|
+
if (!open) return;
|
|
1041
|
+
open = false;
|
|
1042
|
+
Module.sequenceFree(handle);
|
|
1043
|
+
},
|
|
1044
|
+
};
|
|
1045
|
+
},
|
|
756
1046
|
};
|
|
757
1047
|
}
|
|
758
1048
|
|