Skip to content

Writing Files

Basic Writing

// 1. Define schemas
hipo::schema schemaPart("event::particle", 100, 1);
schemaPart.parse("pid/S,px/F,py/F,pz/F");

// 2. Register schemas with writer BEFORE open()
hipo::writer writer;
writer.getDictionary().addSchema(schemaPart);
writer.open("output.hipo");

// 3. Write events
hipo::event event;
for (int i = 0; i < 1000; i++) {
    int nrows = 2 + rand() % 10;
    hipo::bank bank(schemaPart, nrows);

    for (int row = 0; row < nrows; row++) {
        bank.putShort("pid", row, 211);
        bank.putFloat("px", row, 0.5f * row);
        bank.putFloat("py", row, 0.3f * row);
        bank.putFloat("pz", row, 1.0f);
    }

    event.reset();
    event.addStructure(bank);
    writer.addEvent(event);
}

// 4. Close (writes trailer)
writer.close();

Important

Always call writer.close() to finalize the file. It writes the trailer (record index) needed for random access.

Multiple Banks Per Event

hipo::schema schemaPart("event::particle", 100, 1);
schemaPart.parse("pid/S,px/F,py/F,pz/F");

hipo::schema schemaDet("event::detector", 100, 2);
schemaDet.parse("pindex/I,detectorid/I,x/F,y/F,z/F,time/F,energy/F");

hipo::writer writer;
writer.getDictionary().addSchema(schemaPart);
writer.getDictionary().addSchema(schemaDet);
writer.open("output.hipo");

hipo::event event;
for (int i = 0; i < 25000; i++) {
    hipo::bank partBank(schemaPart, 5);
    hipo::bank detBank(schemaDet, 10);

    // fill banks...

    event.reset();
    event.addStructure(partBank);
    event.addStructure(detBank);
    writer.addEvent(event);
}

writer.close();

User Configuration

Store metadata as key-value pairs:

writer.addUserConfig("run", "12345");
writer.addUserConfig("beam_energy", "10.6");
writer.addUserConfig("target", "liquid_hydrogen");

// Must be called before open()
writer.open("output.hipo");

Read it back:

hipo::reader reader;
reader.open("output.hipo");
std::string run = reader.readUserConfig("run");

Copy/Filter Pattern

Read events from one file, optionally filter or modify, write to another:

hipo::reader reader;
reader.open("input.hipo");

hipo::dictionary dict;
reader.readDictionary(dict);

hipo::writer writer;
writer.addDictionary(dict);
writer.open("filtered.hipo");

hipo::event event;
hipo::bank particles(dict.getSchema("REC::Particle"));

while (reader.next()) {
    reader.read(event);
    event.read(particles);

    // Filter: only keep events with electrons
    bool hasElectron = false;
    for (int row = 0; row < particles.getRows(); row++) {
        if (particles.getInt("pid", row) == 11) {
            hasElectron = true;
            break;
        }
    }

    if (hasElectron) {
        writer.addEvent(event);
    }
}

writer.close();

Generic Bank Filling

Fill any bank generically based on its schema:

void fillRandom(hipo::bank& bank) {
    int nrows = bank.getRows();
    int ncols = bank.getSchema().getEntries();

    for (int row = 0; row < nrows; row++) {
        for (int col = 0; col < ncols; col++) {
            int type = bank.getSchema().getEntryType(col);
            const char* name = bank.getSchema().getEntryName(col).c_str();

            switch (type) {
                case hipo::kByte:
                case hipo::kShort:
                case hipo::kInt:
                    bank.putInt(name, row, rand() % 100);
                    break;
                case hipo::kFloat:
                    bank.putFloat(name, row, (float)rand() / RAND_MAX);
                    break;
                case hipo::kDouble:
                    bank.putDouble(name, row, (double)rand() / RAND_MAX);
                    break;
                case hipo::kLong:
                    bank.putLong(name, row, rand());
                    break;
            }
        }
    }
}