diff --git a/demo/node/rntuple_test.js b/demo/node/rntuple_test.js index c7706001f..149f2077a 100644 --- a/demo/node/rntuple_test.js +++ b/demo/node/rntuple_test.js @@ -1,18 +1,18 @@ -import { version, openFile } from 'jsroot'; +import { version, openFile, TSelector } from 'jsroot'; -import { readHeaderFooter } from 'jsroot/rntuple'; +import { readHeaderFooter, readEntry, rntupleProcess } from 'jsroot/rntuple'; console.log(`JSROOT version ${version}`); // const file = await openFile('https://jsroot.gsi.de/files/tmp/ntpl001_staff.root'), // rntuple = await file.readObject('Staff'); -const file = await openFile('simple.root'), -rntuple = await file.readObject('myNtuple'); +const file = await openFile('./rntuple_test.root'), +rntuple = await file.readObject('Data'); await readHeaderFooter(rntuple); console.log('Performing Validations and debugging info'); -if (rntuple.builder?.name !== 'Staff') +if (rntuple.builder?.name !== 'Data') console.error('FAILURE: name differs from expected'); else console.log('OK: name is', rntuple.builder?.name); @@ -21,7 +21,7 @@ else if (rntuple.builder?.description !== '') console.error('FAILURE: description should be the empty string'); else - console.log('OK: description is', rntuple.builder.description); + console.log('OK: description is empty string'); if (rntuple.builder?.xxhash3 === undefined || rntuple.builder.xxhash3 === null) console.warn('WARNING: xxhash3 is missing'); @@ -41,11 +41,11 @@ else { else console.log(`OK: Field ${i}: ${field.fieldName} (${field.typeName})`); if (i === 0) { - if (field.fieldName !== 'Category' || field.typeName !== 'std::int32_t') - console.error(`FAILURE: First field should be 'Category (std::int32_t)' but got '${field.fieldName} (${field.typeName})'`); + if (field.fieldName !== 'IntField' || field.typeName !== 'std::int32_t') + console.error(`FAILURE: First field should be 'IntField (std::int32_t)' but got '${field.fieldName} (${field.typeName})'`); } else if (i === rntuple.builder.fieldDescriptors.length - 1){ - if (field.fieldName !== 'Nation' || field.typeName !== 'std::string') - console.error(`FAILURE: Last field should be 'Nation (std::string)' but got '${field.fieldName} (${field.typeName})'`); + if (field.fieldName !== 'StringField' || field.typeName !== 'std::string') + console.error(`FAILURE: Last field should be 'StringField (std::string)' but got '${field.fieldName} (${field.typeName})'`); } } } @@ -64,10 +64,58 @@ else { console.log(`OK: Column ${i} fieldId: ${column.fieldId} `); if (i === 0) { if (column.fieldId !== 0) - console.error('FAILURE: First column should be for fieldId 0 (Category)'); + console.error('FAILURE: First column should be for fieldId 0 (IntField)'); } else if (i === rntuple.builder.columnDescriptors.length - 1){ - if (column.fieldId !== 10) - console.error('FAILURE: Last column should be for fieldId 10 (Nation)'); + if (column.fieldId !== 3) + console.error('FAILURE: Last column should be for fieldId 3 (StringField)'); + } + } +} + +// Setup selector to process all fields (so cluster gets loaded) +const selector = new TSelector(), + fields = ['IntField', 'FloatField', 'DoubleField', 'StringField']; +for (const f of fields) selector.addBranch(f); + +selector.Begin = () => { + console.log('\nBegin processing to load cluster data...'); +}; +selector.Process = function() {}; +selector.Terminate = () => { + console.log('Finished dummy processing'); +}; + +// Run rntupleProcess to ensure cluster is loaded +await rntupleProcess(rntuple, selector); + +// Now validate entry data +const EPSILON = 1e-10; + +for (let entryIndex = 0; entryIndex < 10; ++entryIndex) { + console.log(`\nChecking entry ${entryIndex}:`); + + const expected = { + IntField: entryIndex, + FloatField: entryIndex * entryIndex, + DoubleField: entryIndex * 0.5, + StringField: `entry_${entryIndex}` + }; + + for (const field of fields) { + try { + const value = readEntry(rntuple, field, entryIndex), + expectedValue = expected[field], + + pass = typeof value === 'number' + ? Math.abs(value - expectedValue) < EPSILON + : value === expectedValue; + + if (!pass) + console.error(`FAILURE: ${field} at entry ${entryIndex} expected ${expectedValue}, got ${value}`); + else + console.log(`OK: ${field} at entry ${entryIndex} = ${value}`); + } catch (err) { + console.error(`ERROR: Failed to read ${field} at entry ${entryIndex}: ${err.message}`); } } } \ No newline at end of file diff --git a/demo/node/rntuple_test.root b/demo/node/rntuple_test.root new file mode 100644 index 000000000..28830eb60 Binary files /dev/null and b/demo/node/rntuple_test.root differ diff --git a/modules/rntuple.mjs b/modules/rntuple.mjs index 4381627db..fba4af2dc 100644 --- a/modules/rntuple.mjs +++ b/modules/rntuple.mjs @@ -928,4 +928,4 @@ async function tupleHierarchy(tuple_node, tuple) { }); } -export { tupleHierarchy, readHeaderFooter, RBufferReader, rntupleProcess }; \ No newline at end of file +export { tupleHierarchy, readHeaderFooter, RBufferReader, rntupleProcess, readEntry }; \ No newline at end of file