Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions demo/node/rntuple_test.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ void rntuple_test()
// shared pointers of the given type
auto IntField = model->MakeField<int>("IntField");
auto FloatField = model->MakeField<float>("FloatField");
auto Float16Field = model->MakeField<float>("Float16Field");
model->GetMutableField("Float16Field").SetColumnRepresentatives({{ROOT::ENTupleColumnType::kReal16}});

auto Real32Trunc = model->MakeField<float>("Real32Trunc");
dynamic_cast<ROOT::RRealField<float> &>(model->GetMutableField("Real32Trunc")).SetTruncated(20);

auto Real32Quant = model->MakeField<float>("Real32Quant");
dynamic_cast<ROOT::RRealField<float> &>(model->GetMutableField("Real32Quant")).SetQuantized(0., 1., 14);

auto DoubleField = model->MakeField<double>("DoubleField");
auto StringField = model->MakeField<std::string>("StringField");
auto BoolField = model->MakeField<bool>("BoolField");
Expand All @@ -56,8 +65,6 @@ void rntuple_test()
auto MapIntDouble = model->MakeField<std::map<int,double>>("MapIntDouble");
auto MapStringBool = model->MakeField<std::map<std::string,bool>>("MapStringBool");



// We hand-over the data model to a newly created ntuple of name "F", stored in kNTupleFileName
// In return, we get a unique pointer to an ntuple that we can fill
auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "Data", kNTupleFileName);
Expand All @@ -66,6 +73,11 @@ void rntuple_test()

*IntField = i;
*FloatField = i*i;

*Float16Field = 0.1987333 * i; // stored as 16 bits float
*Real32Trunc = 123.45 * i; // here only 20 bits preserved
*Real32Quant = 0.03 * (i % 30); // value should be inside [0..1]

*DoubleField = 0.5 * i;
*StringField = "entry_" + std::to_string(i);
*BoolField = (i % 3 == 1);
Expand Down Expand Up @@ -112,8 +124,6 @@ void rntuple_test()
}
Vect2Float->emplace_back(vf);
Vect2Bool->emplace_back(vb);


}

writer->Fill();
Expand Down
18 changes: 13 additions & 5 deletions demo/node/rntuple_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,30 @@ else {

// Setup selector to process all fields (so cluster gets loaded)
const selector = new TSelector(),
fields = ['IntField', 'FloatField', 'DoubleField', 'StringField', 'BoolField',
fields = ['IntField', 'FloatField', 'DoubleField',
'Float16Field', 'Real32Trunc', 'Real32Quant',
'StringField', 'BoolField',
'ArrayInt', 'VariantField', 'TupleField',
'VectString', 'VectInt', 'VectBool', 'Vect2Float', 'Vect2Bool', 'MultisetField',
'MapStringFloat', 'MapIntDouble', 'MapStringBool'];
'MapStringFloat', 'MapIntDouble', 'MapStringBool'],
epsilonValues = { Real32Trunc: 0.3, Real32Quant: 1e-4, Float16Field: 1e-2 };

for (const f of fields)
selector.addBranch(f);

selector.Begin = () => {
console.log('\nBegin processing to load cluster data...');
};


// Now validate entry data
const EPSILON = 1e-7;

let any_error = false;

function compare(expected, value) {
function compare(expected, value, eps) {
if (typeof expected === 'number')
return Math.abs(value - expected) < EPSILON;
return Math.abs(value - expected) < (eps ?? EPSILON);
if (typeof expected === 'object') {
if (expected.length !== undefined) {
if (expected.length !== value.length)
Expand All @@ -123,6 +128,9 @@ selector.Process = function(entryIndex) {
IntField: entryIndex,
FloatField: entryIndex * entryIndex,
DoubleField: entryIndex * 0.5,
Float16Field: entryIndex * 0.1987333,
Real32Trunc: 123.45 * entryIndex,
Real32Quant: 0.03 * (entryIndex % 30),
StringField: `entry_${entryIndex}`,
BoolField: entryIndex % 3 === 1,
ArrayInt: [entryIndex + 1, entryIndex + 2, entryIndex + 3, entryIndex + 4, entryIndex + 5],
Expand Down Expand Up @@ -172,7 +180,7 @@ selector.Process = function(entryIndex) {
const value = this.tgtobj[field],
expected = expectedValues[field];

if (!compare(expected, value)) {
if (!compare(expected, value, epsilonValues[field])) {
console.error(`FAILURE: ${field} at entry ${entryIndex} expected ${JSON.stringify(expected)}, got ${JSON.stringify(value)}`);
any_error = true;
} else
Expand Down
Binary file modified demo/node/rntuple_test.root
Binary file not shown.
57 changes: 47 additions & 10 deletions modules/rntuple.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -852,18 +852,59 @@ class ReaderItem {
break;
case kReal16:
this.func = function(obj) {
obj[this.name] = this.view.getUint16(this.o, LITTLE_ENDIAN);
const value = this.view.getUint16(this.o, LITTLE_ENDIAN);
this.shift_o(2);
// reimplementing of HalfToFloat
let fbits = (value & 0x8000) << 16,
abs = value & 0x7FFF;
if (abs) {
fbits |= 0x38000000 << (abs >= 0x7C00 ? 1 : 0);
for (; abs < 0x400; abs <<= 1, fbits -= 0x800000);
fbits += abs << 13;
}
this.buf.setUint32(0, fbits, true);
obj[this.name] = this.buf.getFloat32(0, true);
};
this.sz = 2;
this.buf = new DataView(new ArrayBuffer(4), 0);
break;
case kReal32Trunc:
case kReal32Quant:
this.nbits = this.column.bitsOnStorage;
if (this.coltype === kReal32Trunc)
this.buf = new DataView(new ArrayBuffer(4), 0);
else {
this.factor = (this.column.maxValue - this.column.minValue) / ((1 << this.nbits) - 1);
this.min = this.column.minValue;
}

this.func = function(obj) {
obj[this.name] = this.view.getUint32(this.o, LITTLE_ENDIAN);
this.shift_o(4);
let res = 0, len = this.nbits;
// extract nbits from the
while (len > 0) {
if (this.o2 === 0) {
this.byte = this.view.getUint8(this.o);
this.o2 = 8; // number of bits in the value
}
const pos = this.nbits - len; // extracted bits
if (len >= this.o2) {
res |= (this.byte & ((1 << this.o2) - 1)) << pos; // get all remaining bits
len -= this.o2;
this.o2 = 0;
this.shift_o(1);
} else {
res |= (this.byte & ((1 << len) - 1)) << pos; // get only len bits from the value
this.o2 -= len;
this.byte >>= len;
len = 0;
}
}
if (this.buf) {
this.buf.setUint32(0, res << (32 - this.nbits), true);
obj[this.name] = this.buf.getFloat32(0, true);
} else
obj[this.name] = res * this.factor + this.min;
};
this.sz = 4;
break;
case kInt64:
case kIndex64:
Expand Down Expand Up @@ -993,12 +1034,8 @@ class ReaderItem {
async unzipBlob(blob, cluster_locations, page_indx) {
const colEntry = cluster_locations[this.id], // Access column entry
numElements = Number(colEntry.pages[page_indx].numElements),
elementSize = this.column.bitsOnStorage / 8;

let expectedSize = numElements * elementSize;
// Special handling for boolean fields
if (this.coltype === kBit)
expectedSize = Math.ceil(numElements / 8);
elementSize = this.column.bitsOnStorage / 8,
expectedSize = Math.ceil(numElements * elementSize);

// Check if data is compressed
if ((colEntry.compression === 0) || (blob.byteLength === expectedSize))
Expand Down
Loading