From 87a68f918ddacd2a469aea0c863ea99d164c6f04 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Nov 2025 11:25:20 +0000 Subject: [PATCH 1/5] refactor: Extract common Data1D processing logic from sync modifiers - Created shared processData1D helper function in modifier.ts - Refactored synccomputesmodifier.ts to use shared helper - Refactored syncfixesmodifier.ts to use shared helper - Refactored syncvariablesmodifier.ts to use shared helper - Reduced code duplication from ~125 lines per file to ~10-15 lines - Ensures consistent WASM memory cleanup across all modifiers Fixes #185 --- src/modifiers/modifier.ts | 90 ++++++++++++++++++++++++++ src/modifiers/synccomputesmodifier.ts | 77 ++++------------------ src/modifiers/syncfixesmodifier.ts | 76 ++++------------------ src/modifiers/syncvariablesmodifier.ts | 76 ++++------------------ 4 files changed, 123 insertions(+), 196 deletions(-) diff --git a/src/modifiers/modifier.ts b/src/modifiers/modifier.ts index 4c0e43bf..6d42802d 100644 --- a/src/modifiers/modifier.ts +++ b/src/modifiers/modifier.ts @@ -1,10 +1,100 @@ import { ModifierInput, ModifierOutput } from "./types"; +import { LMPModifier, Data1D } from "../types"; interface ModifierProps { name: string; active: boolean; } +export interface ProcessedData1D { + data1D: Data1D | undefined; + hasData1D: boolean; + clearPerSync: boolean; +} + +/** + * Shared helper function to process Data1D from LMPModifier. + * Extracts common logic for syncing computes, fixes, and variables. + */ +export function processData1D( + lmpModifier: LMPModifier, + data1D: Data1D | undefined, + input: ModifierInput, + everything: boolean, + syncDataPoints: boolean +): ProcessedData1D { + // Get data1DNamesWrapper and extract size, then delete immediately + const data1DNamesWrapper = lmpModifier.getData1DNames(); + const hasData1D = data1DNamesWrapper.size() > 0; + const data1DNamesSize = data1DNamesWrapper.size(); + data1DNamesWrapper.delete(); // Delete WASM wrapper to prevent memory leak + + if (data1DNamesSize === 0) { + return { data1D, hasData1D, clearPerSync: false }; + } + + const clearPerSync = lmpModifier.getClearPerSync(); + + if (data1D == null) { + data1D = { + data: [], + labels: [], + }; + } + + if ((everything || syncDataPoints) && data1D) { + // Data points is only for plotting figures + if (clearPerSync) { + // For histograms (compute rdf etc) we don't have time as x axis, so we clear every time + data1D.data = []; + } + + const lengthBeforeWeStart = data1D.data.length; // Used to avoid copying all data every time + + if (data1D.labels.length === 0) { + // First label is never visible + data1D.labels.push("x"); + } + + // Get data1DVector once before the loop for better performance + const data1DVector = lmpModifier.getData1D(); + + for (let j = 0; j < data1DNamesSize; j++) { + const lmpData = data1DVector.get(j); + + if (data1D.labels.length - 1 === j) { + // Add missing labels + data1D.labels.push(lmpData.getLabel()); + } + + const xValuesPointer = lmpData.getXValuesPointer() / 4; + const yValuesPointer = lmpData.getYValuesPointer() / 4; + const xValues = input.wasm.HEAPF32.subarray( + xValuesPointer, + xValuesPointer + lmpData.getNumPoints(), + ) as Float32Array; + const yValues = input.wasm.HEAPF32.subarray( + yValuesPointer, + yValuesPointer + lmpData.getNumPoints(), + ) as Float32Array; + for (let k = lengthBeforeWeStart; k < xValues.length; k++) { + if (j === 0) { + data1D.data.push([xValues[k]]); + } + data1D.data[k].push(yValues[k]); + } + + // Delete the Data1D copy to prevent memory leak + lmpData.delete(); + } + + // Delete the vector wrapper after the loop to prevent memory leak + data1DVector.delete(); + } + + return { data1D, hasData1D, clearPerSync }; +} + class Modifier { public name: string; public key: string; diff --git a/src/modifiers/synccomputesmodifier.ts b/src/modifiers/synccomputesmodifier.ts index 069df3c9..17f8a003 100644 --- a/src/modifiers/synccomputesmodifier.ts +++ b/src/modifiers/synccomputesmodifier.ts @@ -1,5 +1,6 @@ import Modifier from "./modifier"; import { ModifierInput, ModifierOutput } from "./types"; +import { processData1D } from "./modifier"; interface SyncComputesModifierProps { name: string; @@ -52,72 +53,16 @@ class SyncComputesModifier extends Modifier { compute.yLabel = compute.lmpCompute.getYLabel(); compute.scalarValue = compute.lmpCompute.getScalarValue(); - // Get data1DNamesWrapper and extract size, then delete immediately - const data1DNamesWrapper = compute.lmpCompute.getData1DNames(); - compute.hasData1D = data1DNamesWrapper.size() > 0; - const data1DNamesSize = data1DNamesWrapper.size(); - data1DNamesWrapper.delete(); // Delete WASM wrapper to prevent memory leak - - if (data1DNamesSize > 0) { - compute.clearPerSync = compute.lmpCompute.getClearPerSync(); - - if (compute.data1D == null) { - compute.data1D = { - data: [], - labels: [], - }; - } - - if ((everything || compute.syncDataPoints) && compute.data1D) { - // Data points is only for plotting figures - if (compute.clearPerSync) { - // For histograms (compute rdf etc) we don't have time as x axis, so we clear every time - compute.data1D.data = []; - } - - const lengthBeforeWeStart = compute.data1D.data.length; // Used to avoid coping all data every time - - if (compute.data1D.labels.length === 0) { - // First label is never visible - compute.data1D.labels.push("x"); - } - - // Get data1DVector once before the loop for better performance - const data1DVector = compute.lmpCompute.getData1D(); - - for (let j = 0; j < data1DNamesSize; j++) { - const lmpData = data1DVector.get(j); - - if (compute.data1D.labels.length - 1 === j) { - // Add missing labels - compute.data1D.labels.push(lmpData.getLabel()); - } - - const xValuesPointer = lmpData.getXValuesPointer() / 4; - const yValuesPointer = lmpData.getYValuesPointer() / 4; - const xValues = input.wasm.HEAPF32.subarray( - xValuesPointer, - xValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - const yValues = input.wasm.HEAPF32.subarray( - yValuesPointer, - yValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - for (let k = lengthBeforeWeStart; k < xValues.length; k++) { - if (j === 0) { - compute.data1D.data.push([xValues[k]]); - } - compute.data1D.data[k].push(yValues[k]); - } - - // Delete the Data1D copy to prevent memory leak - lmpData.delete(); - } - - // Delete the vector wrapper after the loop to prevent memory leak - data1DVector.delete(); - } - } + const processed = processData1D( + compute.lmpCompute, + compute.data1D, + input, + everything, + compute.syncDataPoints, + ); + compute.data1D = processed.data1D; + compute.hasData1D = processed.hasData1D; + compute.clearPerSync = processed.clearPerSync; } output.computes[name] = compute; } diff --git a/src/modifiers/syncfixesmodifier.ts b/src/modifiers/syncfixesmodifier.ts index d1d54716..d0625e80 100644 --- a/src/modifiers/syncfixesmodifier.ts +++ b/src/modifiers/syncfixesmodifier.ts @@ -1,5 +1,6 @@ import Modifier from "./modifier"; import { ModifierInput, ModifierOutput } from "./types"; +import { processData1D } from "./modifier"; interface SyncFixesModifierProps { name: string; @@ -49,71 +50,16 @@ class SyncFixesModifier extends Modifier { fix.yLabel = fix.lmpFix.getYLabel(); fix.scalarValue = fix.lmpFix.getScalarValue(); - // Get data1DNamesWrapper and extract size, then delete immediately - const data1DNamesWrapper = fix.lmpFix.getData1DNames(); - fix.hasData1D = data1DNamesWrapper.size() > 0; - const data1DNamesSize = data1DNamesWrapper.size(); - data1DNamesWrapper.delete(); // Delete WASM wrapper to prevent memory leak - - if (data1DNamesSize > 0) { - fix.clearPerSync = fix.lmpFix.getClearPerSync(); - if (fix.data1D == null) { - fix.data1D = { - data: [], - labels: [], - }; - } - - if ((everything || fix.syncDataPoints) && fix.data1D) { - // Data points is only for plotting figures - if (fix.clearPerSync) { - // For histograms (compute rdf etc) we don't have time as x axis, so we clear every time - fix.data1D.data = []; - } - - const lengthBeforeWeStart = fix.data1D.data.length; // Used to avoid coping all data every time - - if (fix.data1D.labels.length === 0) { - // First label is never visible - fix.data1D.labels.push("x"); - } - - // Get data1DVector once before the loop for better performance - const data1DVector = fix.lmpFix.getData1D(); - - for (let j = 0; j < data1DNamesSize; j++) { - const lmpData = data1DVector.get(j); - - if (fix.data1D.labels.length - 1 === j) { - // Add missing labels - fix.data1D.labels.push(lmpData.getLabel()); - } - - const xValuesPointer = lmpData.getXValuesPointer() / 4; - const yValuesPointer = lmpData.getYValuesPointer() / 4; - const xValues = input.wasm.HEAPF32.subarray( - xValuesPointer, - xValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - const yValues = input.wasm.HEAPF32.subarray( - yValuesPointer, - yValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - for (let k = lengthBeforeWeStart; k < xValues.length; k++) { - if (j === 0) { - fix.data1D.data.push([xValues[k]]); - } - fix.data1D.data[k].push(yValues[k]); - } - - // Delete the Data1D copy to prevent memory leak - lmpData.delete(); - } - - // Delete the vector wrapper after the loop to prevent memory leak - data1DVector.delete(); - } - } + const processed = processData1D( + fix.lmpFix, + fix.data1D, + input, + everything, + fix.syncDataPoints, + ); + fix.data1D = processed.data1D; + fix.hasData1D = processed.hasData1D; + fix.clearPerSync = processed.clearPerSync; output.fixes[name] = fix; } }; diff --git a/src/modifiers/syncvariablesmodifier.ts b/src/modifiers/syncvariablesmodifier.ts index f84923d6..9bd380ad 100644 --- a/src/modifiers/syncvariablesmodifier.ts +++ b/src/modifiers/syncvariablesmodifier.ts @@ -1,5 +1,6 @@ import Modifier from "./modifier"; import { ModifierInput, ModifierOutput } from "./types"; +import { processData1D } from "./modifier"; interface SyncVariablesModifierProps { name: string; @@ -51,71 +52,16 @@ class SyncVariablesModifier extends Modifier { variable.scalarValue = variable.lmpVariable.getScalarValue(); variable.hasScalarData = variable.lmpVariable.hasScalarData(); - // Get data1DNamesWrapper and extract size, then delete immediately - const data1DNamesWrapper = variable.lmpVariable.getData1DNames(); - variable.hasData1D = data1DNamesWrapper.size() > 0; - const data1DNamesSize = data1DNamesWrapper.size(); - data1DNamesWrapper.delete(); // Delete WASM wrapper to prevent memory leak - - if (data1DNamesSize > 0) { - variable.clearPerSync = variable.lmpVariable.getClearPerSync(); - if (variable.data1D == null) { - variable.data1D = { - data: [], - labels: [], - }; - } - - if ((everything || variable.syncDataPoints) && variable.data1D) { - // Data points is only for plotting figures - if (variable.clearPerSync) { - // For histograms (compute rdf etc) we don't have time as x axis, so we clear every time - variable.data1D.data = []; - } - - const lengthBeforeWeStart = variable.data1D.data.length; // Used to avoid coping all data every time - - if (variable.data1D.labels.length === 0) { - // First label is never visible - variable.data1D.labels.push("x"); - } - - // Get data1DVector once before the loop for better performance - const data1DVector = variable.lmpVariable.getData1D(); - - for (let j = 0; j < data1DNamesSize; j++) { - const lmpData = data1DVector.get(j); - - if (variable.data1D.labels.length - 1 === j) { - // Add missing labels - variable.data1D.labels.push(lmpData.getLabel()); - } - - const xValuesPointer = lmpData.getXValuesPointer() / 4; - const yValuesPointer = lmpData.getYValuesPointer() / 4; - const xValues = input.wasm.HEAPF32.subarray( - xValuesPointer, - xValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - const yValues = input.wasm.HEAPF32.subarray( - yValuesPointer, - yValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - for (let k = lengthBeforeWeStart; k < xValues.length; k++) { - if (j === 0) { - variable.data1D.data.push([xValues[k]]); - } - variable.data1D.data[k].push(yValues[k]); - } - - // Delete the Data1D copy to prevent memory leak - lmpData.delete(); - } - - // Delete the vector wrapper after the loop to prevent memory leak - data1DVector.delete(); - } - } + const processed = processData1D( + variable.lmpVariable, + variable.data1D, + input, + everything, + variable.syncDataPoints, + ); + variable.data1D = processed.data1D; + variable.hasData1D = processed.hasData1D; + variable.clearPerSync = processed.clearPerSync; output.variables[name] = variable; } }; From ffc014ec519aa38f6f6c834ed28efd5ce9148d7f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Nov 2025 11:39:59 +0000 Subject: [PATCH 2/5] Address PR review comments: optimize processData1D and use destructuring - Call data1DNamesWrapper.size() once instead of twice - Remove redundant data1D check in processData1D - Use object destructuring in all three sync modifiers for cleaner code --- src/modifiers/modifier.ts | 4 ++-- src/modifiers/synccomputesmodifier.ts | 8 ++++---- src/modifiers/syncfixesmodifier.ts | 8 ++++---- src/modifiers/syncvariablesmodifier.ts | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/modifiers/modifier.ts b/src/modifiers/modifier.ts index 6d42802d..24a63c6c 100644 --- a/src/modifiers/modifier.ts +++ b/src/modifiers/modifier.ts @@ -25,8 +25,8 @@ export function processData1D( ): ProcessedData1D { // Get data1DNamesWrapper and extract size, then delete immediately const data1DNamesWrapper = lmpModifier.getData1DNames(); - const hasData1D = data1DNamesWrapper.size() > 0; const data1DNamesSize = data1DNamesWrapper.size(); + const hasData1D = data1DNamesSize > 0; data1DNamesWrapper.delete(); // Delete WASM wrapper to prevent memory leak if (data1DNamesSize === 0) { @@ -42,7 +42,7 @@ export function processData1D( }; } - if ((everything || syncDataPoints) && data1D) { + if (everything || syncDataPoints) { // Data points is only for plotting figures if (clearPerSync) { // For histograms (compute rdf etc) we don't have time as x axis, so we clear every time diff --git a/src/modifiers/synccomputesmodifier.ts b/src/modifiers/synccomputesmodifier.ts index 17f8a003..153564c0 100644 --- a/src/modifiers/synccomputesmodifier.ts +++ b/src/modifiers/synccomputesmodifier.ts @@ -53,16 +53,16 @@ class SyncComputesModifier extends Modifier { compute.yLabel = compute.lmpCompute.getYLabel(); compute.scalarValue = compute.lmpCompute.getScalarValue(); - const processed = processData1D( + const { data1D, hasData1D, clearPerSync } = processData1D( compute.lmpCompute, compute.data1D, input, everything, compute.syncDataPoints, ); - compute.data1D = processed.data1D; - compute.hasData1D = processed.hasData1D; - compute.clearPerSync = processed.clearPerSync; + compute.data1D = data1D; + compute.hasData1D = hasData1D; + compute.clearPerSync = clearPerSync; } output.computes[name] = compute; } diff --git a/src/modifiers/syncfixesmodifier.ts b/src/modifiers/syncfixesmodifier.ts index d0625e80..d230f5fc 100644 --- a/src/modifiers/syncfixesmodifier.ts +++ b/src/modifiers/syncfixesmodifier.ts @@ -50,16 +50,16 @@ class SyncFixesModifier extends Modifier { fix.yLabel = fix.lmpFix.getYLabel(); fix.scalarValue = fix.lmpFix.getScalarValue(); - const processed = processData1D( + const { data1D, hasData1D, clearPerSync } = processData1D( fix.lmpFix, fix.data1D, input, everything, fix.syncDataPoints, ); - fix.data1D = processed.data1D; - fix.hasData1D = processed.hasData1D; - fix.clearPerSync = processed.clearPerSync; + fix.data1D = data1D; + fix.hasData1D = hasData1D; + fix.clearPerSync = clearPerSync; output.fixes[name] = fix; } }; diff --git a/src/modifiers/syncvariablesmodifier.ts b/src/modifiers/syncvariablesmodifier.ts index 9bd380ad..920ddb5c 100644 --- a/src/modifiers/syncvariablesmodifier.ts +++ b/src/modifiers/syncvariablesmodifier.ts @@ -52,16 +52,16 @@ class SyncVariablesModifier extends Modifier { variable.scalarValue = variable.lmpVariable.getScalarValue(); variable.hasScalarData = variable.lmpVariable.hasScalarData(); - const processed = processData1D( + const { data1D, hasData1D, clearPerSync } = processData1D( variable.lmpVariable, variable.data1D, input, everything, variable.syncDataPoints, ); - variable.data1D = processed.data1D; - variable.hasData1D = processed.hasData1D; - variable.clearPerSync = processed.clearPerSync; + variable.data1D = data1D; + variable.hasData1D = hasData1D; + variable.clearPerSync = clearPerSync; output.variables[name] = variable; } }; From 544b2e6c37843fb62f0771ac11efba3582a33a21 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Nov 2025 11:53:03 +0000 Subject: [PATCH 3/5] Address additional PR review comments: optimize loop and use Object.assign - Optimize loop in processData1D: separate j===0 logic and avoid fetching xValues when j>0 - Remove redundant Float32Array type cast (HEAPF32.subarray already returns Float32Array) - Use Object.assign instead of destructuring in sync modifiers for better conciseness --- src/modifiers/modifier.ts | 26 ++++++++++++++++---------- src/modifiers/synccomputesmodifier.ts | 7 ++----- src/modifiers/syncfixesmodifier.ts | 7 ++----- src/modifiers/syncvariablesmodifier.ts | 7 ++----- 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/modifiers/modifier.ts b/src/modifiers/modifier.ts index 24a63c6c..9ba7690b 100644 --- a/src/modifiers/modifier.ts +++ b/src/modifiers/modifier.ts @@ -67,21 +67,27 @@ export function processData1D( data1D.labels.push(lmpData.getLabel()); } - const xValuesPointer = lmpData.getXValuesPointer() / 4; + const numPoints = lmpData.getNumPoints(); const yValuesPointer = lmpData.getYValuesPointer() / 4; - const xValues = input.wasm.HEAPF32.subarray( - xValuesPointer, - xValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; const yValues = input.wasm.HEAPF32.subarray( yValuesPointer, - yValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - for (let k = lengthBeforeWeStart; k < xValues.length; k++) { - if (j === 0) { + yValuesPointer + numPoints, + ); + + if (j === 0) { + const xValuesPointer = lmpData.getXValuesPointer() / 4; + const xValues = input.wasm.HEAPF32.subarray( + xValuesPointer, + xValuesPointer + numPoints, + ); + for (let k = lengthBeforeWeStart; k < numPoints; k++) { data1D.data.push([xValues[k]]); + data1D.data[k].push(yValues[k]); + } + } else { + for (let k = lengthBeforeWeStart; k < numPoints; k++) { + data1D.data[k].push(yValues[k]); } - data1D.data[k].push(yValues[k]); } // Delete the Data1D copy to prevent memory leak diff --git a/src/modifiers/synccomputesmodifier.ts b/src/modifiers/synccomputesmodifier.ts index 153564c0..b8896aa5 100644 --- a/src/modifiers/synccomputesmodifier.ts +++ b/src/modifiers/synccomputesmodifier.ts @@ -53,16 +53,13 @@ class SyncComputesModifier extends Modifier { compute.yLabel = compute.lmpCompute.getYLabel(); compute.scalarValue = compute.lmpCompute.getScalarValue(); - const { data1D, hasData1D, clearPerSync } = processData1D( + Object.assign(compute, processData1D( compute.lmpCompute, compute.data1D, input, everything, compute.syncDataPoints, - ); - compute.data1D = data1D; - compute.hasData1D = hasData1D; - compute.clearPerSync = clearPerSync; + )); } output.computes[name] = compute; } diff --git a/src/modifiers/syncfixesmodifier.ts b/src/modifiers/syncfixesmodifier.ts index d230f5fc..285efda0 100644 --- a/src/modifiers/syncfixesmodifier.ts +++ b/src/modifiers/syncfixesmodifier.ts @@ -50,16 +50,13 @@ class SyncFixesModifier extends Modifier { fix.yLabel = fix.lmpFix.getYLabel(); fix.scalarValue = fix.lmpFix.getScalarValue(); - const { data1D, hasData1D, clearPerSync } = processData1D( + Object.assign(fix, processData1D( fix.lmpFix, fix.data1D, input, everything, fix.syncDataPoints, - ); - fix.data1D = data1D; - fix.hasData1D = hasData1D; - fix.clearPerSync = clearPerSync; + )); output.fixes[name] = fix; } }; diff --git a/src/modifiers/syncvariablesmodifier.ts b/src/modifiers/syncvariablesmodifier.ts index 920ddb5c..7e3306a5 100644 --- a/src/modifiers/syncvariablesmodifier.ts +++ b/src/modifiers/syncvariablesmodifier.ts @@ -52,16 +52,13 @@ class SyncVariablesModifier extends Modifier { variable.scalarValue = variable.lmpVariable.getScalarValue(); variable.hasScalarData = variable.lmpVariable.hasScalarData(); - const { data1D, hasData1D, clearPerSync } = processData1D( + Object.assign(variable, processData1D( variable.lmpVariable, variable.data1D, input, everything, variable.syncDataPoints, - ); - variable.data1D = data1D; - variable.hasData1D = hasData1D; - variable.clearPerSync = clearPerSync; + )); output.variables[name] = variable; } }; From b33e5b2c41e01f1f5afe98e8c59504cb0eba83ef Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Nov 2025 11:55:25 +0000 Subject: [PATCH 4/5] Checkpoint before follow-up message Co-authored-by: anders.hafreager --- src/modifiers/modifier.ts | 26 ++++++++++---------------- src/modifiers/synccomputesmodifier.ts | 7 +++++-- src/modifiers/syncfixesmodifier.ts | 7 +++++-- src/modifiers/syncvariablesmodifier.ts | 7 +++++-- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/modifiers/modifier.ts b/src/modifiers/modifier.ts index 9ba7690b..24a63c6c 100644 --- a/src/modifiers/modifier.ts +++ b/src/modifiers/modifier.ts @@ -67,27 +67,21 @@ export function processData1D( data1D.labels.push(lmpData.getLabel()); } - const numPoints = lmpData.getNumPoints(); + const xValuesPointer = lmpData.getXValuesPointer() / 4; const yValuesPointer = lmpData.getYValuesPointer() / 4; + const xValues = input.wasm.HEAPF32.subarray( + xValuesPointer, + xValuesPointer + lmpData.getNumPoints(), + ) as Float32Array; const yValues = input.wasm.HEAPF32.subarray( yValuesPointer, - yValuesPointer + numPoints, - ); - - if (j === 0) { - const xValuesPointer = lmpData.getXValuesPointer() / 4; - const xValues = input.wasm.HEAPF32.subarray( - xValuesPointer, - xValuesPointer + numPoints, - ); - for (let k = lengthBeforeWeStart; k < numPoints; k++) { + yValuesPointer + lmpData.getNumPoints(), + ) as Float32Array; + for (let k = lengthBeforeWeStart; k < xValues.length; k++) { + if (j === 0) { data1D.data.push([xValues[k]]); - data1D.data[k].push(yValues[k]); - } - } else { - for (let k = lengthBeforeWeStart; k < numPoints; k++) { - data1D.data[k].push(yValues[k]); } + data1D.data[k].push(yValues[k]); } // Delete the Data1D copy to prevent memory leak diff --git a/src/modifiers/synccomputesmodifier.ts b/src/modifiers/synccomputesmodifier.ts index b8896aa5..17f8a003 100644 --- a/src/modifiers/synccomputesmodifier.ts +++ b/src/modifiers/synccomputesmodifier.ts @@ -53,13 +53,16 @@ class SyncComputesModifier extends Modifier { compute.yLabel = compute.lmpCompute.getYLabel(); compute.scalarValue = compute.lmpCompute.getScalarValue(); - Object.assign(compute, processData1D( + const processed = processData1D( compute.lmpCompute, compute.data1D, input, everything, compute.syncDataPoints, - )); + ); + compute.data1D = processed.data1D; + compute.hasData1D = processed.hasData1D; + compute.clearPerSync = processed.clearPerSync; } output.computes[name] = compute; } diff --git a/src/modifiers/syncfixesmodifier.ts b/src/modifiers/syncfixesmodifier.ts index 285efda0..d0625e80 100644 --- a/src/modifiers/syncfixesmodifier.ts +++ b/src/modifiers/syncfixesmodifier.ts @@ -50,13 +50,16 @@ class SyncFixesModifier extends Modifier { fix.yLabel = fix.lmpFix.getYLabel(); fix.scalarValue = fix.lmpFix.getScalarValue(); - Object.assign(fix, processData1D( + const processed = processData1D( fix.lmpFix, fix.data1D, input, everything, fix.syncDataPoints, - )); + ); + fix.data1D = processed.data1D; + fix.hasData1D = processed.hasData1D; + fix.clearPerSync = processed.clearPerSync; output.fixes[name] = fix; } }; diff --git a/src/modifiers/syncvariablesmodifier.ts b/src/modifiers/syncvariablesmodifier.ts index 7e3306a5..9bd380ad 100644 --- a/src/modifiers/syncvariablesmodifier.ts +++ b/src/modifiers/syncvariablesmodifier.ts @@ -52,13 +52,16 @@ class SyncVariablesModifier extends Modifier { variable.scalarValue = variable.lmpVariable.getScalarValue(); variable.hasScalarData = variable.lmpVariable.hasScalarData(); - Object.assign(variable, processData1D( + const processed = processData1D( variable.lmpVariable, variable.data1D, input, everything, variable.syncDataPoints, - )); + ); + variable.data1D = processed.data1D; + variable.hasData1D = processed.hasData1D; + variable.clearPerSync = processed.clearPerSync; output.variables[name] = variable; } }; From f7e3a9c7c2b5d68f993120907c2ec88342f7af68 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 1 Nov 2025 11:55:34 +0000 Subject: [PATCH 5/5] Improve loop logic in processData1D helper function - Separate j===0 and j>0 logic for better clarity - Avoid fetching xValues when j>0 (performance improvement) - Store numPoints once to avoid repeated calls - Remove redundant Float32Array type cast --- src/modifiers/modifier.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/modifiers/modifier.ts b/src/modifiers/modifier.ts index 24a63c6c..9ba7690b 100644 --- a/src/modifiers/modifier.ts +++ b/src/modifiers/modifier.ts @@ -67,21 +67,27 @@ export function processData1D( data1D.labels.push(lmpData.getLabel()); } - const xValuesPointer = lmpData.getXValuesPointer() / 4; + const numPoints = lmpData.getNumPoints(); const yValuesPointer = lmpData.getYValuesPointer() / 4; - const xValues = input.wasm.HEAPF32.subarray( - xValuesPointer, - xValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; const yValues = input.wasm.HEAPF32.subarray( yValuesPointer, - yValuesPointer + lmpData.getNumPoints(), - ) as Float32Array; - for (let k = lengthBeforeWeStart; k < xValues.length; k++) { - if (j === 0) { + yValuesPointer + numPoints, + ); + + if (j === 0) { + const xValuesPointer = lmpData.getXValuesPointer() / 4; + const xValues = input.wasm.HEAPF32.subarray( + xValuesPointer, + xValuesPointer + numPoints, + ); + for (let k = lengthBeforeWeStart; k < numPoints; k++) { data1D.data.push([xValues[k]]); + data1D.data[k].push(yValues[k]); + } + } else { + for (let k = lengthBeforeWeStart; k < numPoints; k++) { + data1D.data[k].push(yValues[k]); } - data1D.data[k].push(yValues[k]); } // Delete the Data1D copy to prevent memory leak