/* Copyright (c) 2019, Anthony Latorre * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #include "Record_Info.h" #include #include "zdab_utils.h" #include "pack2b.h" #include /* for size_t */ #include /* for fprintf() */ #include "event.h" #include "zebra.h" #include "misc.h" #include "sno_charge.h" char zdab_err[256]; /* Mean of high-half point distribution. */ static double MEAN_HIPT = 46.0; /* Average value for the QHS/QHL/QLX pedestal. * * Note: This is *not* actually accurate. I just need something roughly correct * to "uncalibrate" the Monte Carlo. */ static double MEAN_PEDESTAL = 600.0; size_t get_nhit(event *ev) { /* Returns the number of PMT hits in event `ev`. * * Note: Only hits on normal PMTs which aren't flagged are counted. */ size_t i, nhit; nhit = 0; for (i = 0; i < MAX_PMTS; i++) { if (ev->pmt_hits[i].flags || pmts[i].pmt_type != PMT_NORMAL) continue; if (!ev->pmt_hits[i].hit) continue; nhit++; } return nhit; } /* Returns 1 if the EV is produced by MC, otherwise zero. * * Data type = 10*(1=real, 2=MC) * + 1*(1=SNO, 2=miniSNO) * * See id_data_types in the SNOMAN companion. */ int is_mc(EVBank *ev) { return ev->dtp/10 == 2; } int get_event(zebraFile *f, event *ev, zebraBank *bev) { /* Read all the PMT banks from the zebra file and update `ev`. * * Returns 0 on success, -1 on error. */ int i, rv; PMTBank bpmt; zebraBank b; int id, crate, card, channel; static int pmt_links[] = {KEV_PMT,KEV_OWL,KEV_LG,KEV_FECD,KEV_BUTT,KEV_NECK}; static int pmt_types[] = {PMT_NORMAL,PMT_OWL,PMT_LG,PMT_CALIBRATION,PMT_BUTT,PMT_NECK}; static char *pmt_names[] = {"PMT","OWL","LG","FECD","BUTT","NECK"}; char pmt_type_string[256]; EVBank ev_bank; for (i = 0; i < MAX_PMTS; i++) { ev->pmt_hits[i].hit = 0; } unpack_ev(bev->data, &ev_bank); ev->run = ev_bank.run; ev->gtid = ev_bank.gtr_id; ev->trigger_type = ev_bank.trg_type; ev->trigger_time = ev_bank.gtr; ev->dte = ev_bank.dte; ev->hmsc = ev_bank.hmsc; for (i = 0; i < LEN(pmt_links); i++) { if (bev->links[pmt_links[i]-1] == 0) continue; rv = zebra_get_bank(f,&b,bev->links[pmt_links[i]-1]); if (rv) { fprintf(stderr, "error getting %s bank: %s\n", pmt_names[i], zebra_err); return -1; } while (1) { unpack_pmt(b.data, &bpmt); card = bpmt.pin/1024; crate = (bpmt.pin % 1024)/32; channel = bpmt.pin % 32; id = crate*512 + card*32 + channel; if (id >= MAX_PMTS) { fprintf(stderr, "PMT hit from %i/%i/%i\n", crate, card, channel); return -1; } if (ev->pmt_hits[id].hit) { fprintf(stderr, "%i/%i/%i is in the PMT bank twice!\n", crate, card, channel); } ev->pmt_hits[id].hit = 1; ev->pmt_hits[id].ept = bpmt.ept; ev->pmt_hits[id].qihl = bpmt.pihl; ev->pmt_hits[id].qihs = bpmt.pihs; ev->pmt_hits[id].qilx = bpmt.pilx; ev->pmt_hits[id].ehl = bpmt.ehl; ev->pmt_hits[id].ehs = bpmt.ehs; ev->pmt_hits[id].elx = bpmt.elx; ev->pmt_hits[id].qhl = bpmt.phl; ev->pmt_hits[id].qhs = bpmt.phs; ev->pmt_hits[id].qlx = bpmt.plx; ev->pmt_hits[id].pf = bpmt.pf; ev->pmt_hits[id].pt = bpmt.pt; ev->pmt_hits[id].pt1 = bpmt.pt1; ev->pmt_hits[id].ptm = bpmt.ptm; if (is_mc(&ev_bank)) { /* Use standard time if this is MC since the multiphoton time * isn't calculated for MC. */ ev->pmt_hits[id].t = bpmt.pt; ev->pmt_hits[id].ept = bpmt.pt; ev->pmt_hits[id].pt1 = bpmt.pt; } else { /* Use the multiphoton PCA time since we are looking at high * energy events. */ ev->pmt_hits[id].t = bpmt.ptm; } /* Clear the PMT_FLAG_DIS bit. */ ev->pmt_hits[id].flags &= ~PMT_FLAG_DIS; /* Clear the PMT_FLAG_CHARGE bit. */ ev->pmt_hits[id].flags &= ~PMT_FLAG_CHARGE; /* Make sure we have good calibrations. Technically, we should only * have to check the KPF_DIS bit since according to the SNOMAN * docs: * * The discard bit KPF_DIS of the 1-bit flags KPMT_PF is also * set if any other failure bit, such as KPF_NO_CAL or * KPF_BAD_CAL is set. So only this bit need be tested for PMT * rejection. * * But this isn't true! In run 10,000 GTID 140730 channel 11/6/17 * has the KPF_BAD_CAL bit set but not the KPF_DIS bit set. I also * looked at the SNOMAN code and confirmed that this isn't the * case. */ if (bpmt.pf & (KPF_DIS | KPF_NO_CAL | KPF_BAD_CAL)) ev->pmt_hits[id].flags |= PMT_FLAG_DIS; if (bpmt.qms) ev->pmt_hits[id].flags |= PMT_FLAG_CHARGE; /* Determine the best charge to use in the likelihood function (QHS * or QLX). * * Technically, the charge model only deals with QHS and so my * original plan was to just flag any PMT hit with a railed or bad * QHS and not include it in the likelihood function, but when * testing I noticed that muons close to the PSUP can accidentally * get reconstructed as electrons inside the AV if I ignore railed * QHS values, so instead we use the QLX values when QHS is railed. * * Although the charge model only deals with QHS, I think it should * be close enough that it's OK to use QLX. Both charges are * normalized in the same way, the only difference would be in * their SPE width. * * If both QHS and QLX are railed or have uncalibrated charges * below 300, we flag the PMT and it's not included in the * likelihood function. */ if (is_mc(&ev_bank)) { /* Skip uncalibrated charge check if this is MC. The reason is * that for some reason the uncalibrator in SNOMAN needs the * QSLP tables which aren't available for most runs. According * to Chris Kyba: * * > From summer 2000 on, we never ran charge slopes. I'm not * > sure if we did at the very start in 1999, because I didn't * > always understand what was going on when I was an undergrad * > :-) * * > I never looked at the charge slope data. My best * > recollection of the uncalibrator was everyone saying "it * > doesn't work, don't try to use it". * * Therefore, we ignore it for MC. */ ev->pmt_hits[id].q = bpmt.phs; /* For the uncalibrated charges, multiply the charge by the * mean high-half point and then add a constant offset. */ ev->pmt_hits[id].qihl = fmax(fmin(bpmt.phl*MEAN_HIPT + MEAN_PEDESTAL,4095.0),0.0); ev->pmt_hits[id].qihs = fmax(fmin(bpmt.phs*MEAN_HIPT + MEAN_PEDESTAL,4095.0),0.0); ev->pmt_hits[id].qilx = fmax(fmin(bpmt.plx*MEAN_HIPT + MEAN_PEDESTAL,4095.0),0.0); /* For the ECA calibrated charges, just subtract the offset * from the uncalibrated charges. */ ev->pmt_hits[id].ehl = ev->pmt_hits[id].qihl - MEAN_PEDESTAL; ev->pmt_hits[id].ehs = ev->pmt_hits[id].qihs - MEAN_PEDESTAL; ev->pmt_hits[id].elx = ev->pmt_hits[id].qilx - MEAN_PEDESTAL; } else if (bpmt.pihs < 4095 && bpmt.pihs >= 300) { ev->pmt_hits[id].q = bpmt.phs; } else if (bpmt.pilx < 4095 && bpmt.pilx >= 300) { ev->pmt_hits[id].q = bpmt.plx; } else { ev->pmt_hits[id].q = 0.0; ev->pmt_hits[id].flags |= PMT_FLAG_CHARGE; } /* Flag PMTs with charges below qlo, since otherwise the negative * log likelihood will be nan. */ if (ev->pmt_hits[id].q < get_qlo()) { ev->pmt_hits[id].flags |= PMT_FLAG_CHARGE; } if (pmts[id].pmt_type != pmt_types[i]) { get_pmt_type_string(pmts[id].pmt_type,pmt_type_string); fprintf(stderr, "%i/%i/%i has PMT type %s but expected %s based on bank\n", crate, card, channel, pmt_type_string, pmt_names[i]); } /* The above check prints out a warning on a handful of channels: * * 3/15/9 has PMT type NECK but expected OWL based on bank * 18/0/14 has PMT type INVALID but expected BUTT based on bank * (+ a handful of other INVALID/BUTT discrepancies in crates 18 and 15) * * I sent an email to the SNO mailing list and Stan responded: * * > That PMT ID jogged a neuron somewhere, and I went hunting * > through my email archive. Here is an email I sent Neil 14 years * > ago (?!) after we added the new neck tubes which might explain * > how a neck tube ended up classified as an OWL. When new neck * > tubes were added for the NCD phase, they broke the range-based * > logical PMT numbering: * * > On Tue, 9 Nov 2004 at 09:40:06 AM, Neil wrote: * > > Hi, * > > * > > A new file has been released as should be in the database that has * > > the updated neck tube positions. This file will also be in the new * > > version of snoman to be released today or tomorrow. * > > * > > Neil. * > > * > > Stan Seibert wrote: * > > > * > > > Hi Neil, * > > > * > > > I've noticed several issues in how neck tubes are handled in SNOMAN. * > > > * > > > * The 3 new tubes are plugged into channels 18/15/0, 18/15/10, and * > > > 3/15/9. According to map_ccc_tube.dat, the last two are tube numbers * > > > 9635 and 9655. The first, 18/15/0, currently has the entry -999999, * > > > indicating it is a spare. Is there a more up-to-date version of * > > > map_ccc_tube.dat I should be looking at? I tried reading through * > > > Phil's pmt database for xsnoed, but was unable to find anything that * > > > resembled tube numbers as SNOMAN defines them. * > > > * > > > * > > > * Once that is corrected, I will need to fix ccc_type.for which * > > > decides which PMT list (normal, owl, neck, etc.) each PMT hit goes * > > > into. This will uglify the function a bit because the neck tubes are * > > > no longer in a contiguous block of tube numbers. Numbers 9635 and * > > > 9655 are actually in the OWL range. How should backward compatibility * > > > be handled here? Do I hardcode a run number and check for it? * > > > * > > > * > > > * With that fix, upk_unpacker_zdab_pmt.for will then file the neck * > > > tube in its appropriate list, right? * > > > * > > > * > > > Please let me know if this makes sense and where I can get updated * > > > information. Thanks. * > > > * > > > --- * > > > Stan Seibert * * I also looked at the run in XSNOED and it looks like 3/15/9 * should be an OWL PMT and not a neck PMT. * * Based on the email and the fact that 3/15/9 *should* be an OWL * PMT, I am going to assume that the database that SNOMAN uses to * figure out the PMT types is correct and so reassign the PMT type * based on that. */ pmts[id].pmt_type = pmt_types[i]; if (!b.next) break; rv = zebra_get_bank(f,&b,b.next); if (rv) { fprintf(stderr, "error getting %s bank: %s\n", pmt_names[i], zebra_err); return -1; } } } ev->nhit = get_nhit(ev); return 0; } int isOrphan(aPmtEventRecord *pmtRecord) { /* Returns non-zero if the specified event is an orphan. */ int i; uint32_t *mtc_data = (uint32_t *) &pmtRecord->TriggerCardData; for (i = 0; i < 6; ++i) { if (*mtc_data != 0) return 0; ++mtc_data; } return 1; } // PH 04/23/98 // Swap 4-byte integer/floats between native and external format void swap_int32(int32_t *val_pt, int count) { int32_t *last = val_pt + count; while (val_pt < last) { *val_pt = ((*val_pt << 24) & 0xff000000) | ((*val_pt << 8) & 0x00ff0000) | ((*val_pt >> 8) & 0x0000ff00) | ((*val_pt >> 24) & 0x000000ff); ++val_pt; } return; } // Swap 2-byte integers between native and external format void swap_int16(int16_t *val_pt, int count) { char tmp; int i; for (i=0; ilinks[KEV_FT-1] == 0) { sprintf(zdab_err, "FT link is zero!"); goto err; } rv = zebra_get_bank(f,&ft,ev->links[KEV_FT-1]); if (rv) { sprintf(zdab_err, "error getting FT bank: %s", zebra_err); goto err; } if (ft.links[KFT_FTP-1] == 0) { sprintf(zdab_err, "FTP link is zero!"); goto err; } rv = zebra_get_bank(f,&ftp,ft.links[KFT_FTP-1]); if (rv) { sprintf(zdab_err, "error getting FTP bank: %s", zebra_err); goto err; } if (ftp.links[KFTX_FTXV-1] == 0) { sprintf(zdab_err, "FTXV link is zero!"); goto err; } rv = zebra_get_bank(f,&ftpv,ftp.links[KFTX_FTXV-1]); if (rv) { sprintf(zdab_err, "error getting FTXV bank: %s", zebra_err); goto err; } unpack_ftpv(ftpv.data,bftpv); return 0; err: return -1; } /* Get and unpack the FTXK bank from the FTP fitter. * * Returns 0 if successful, or -1 on error. If there was an error, the error * string is printed to zdab_err. */ int get_ftxk(zebraFile *f, zebraBank *ev, FTXKBank *bftxk) { int rv; zebraBank ft, ftp, ftxa, ftxk; if (ev->links[KEV_FT-1] == 0) { sprintf(zdab_err, "FT link is zero!"); goto err; } rv = zebra_get_bank(f,&ft,ev->links[KEV_FT-1]); if (rv) { sprintf(zdab_err, "error getting FT bank: %s", zebra_err); goto err; } if (ft.links[KFT_FTP-1] == 0) { sprintf(zdab_err, "FTP link is zero!"); goto err; } rv = zebra_get_bank(f,&ftp,ft.links[KFT_FTP-1]); if (rv) { sprintf(zdab_err, "error getting FTP bank: %s", zebra_err); goto err; } if (ftp.links[KFTX_FTXA-1] == 0) { sprintf(zdab_err, "FTXA link is zero!"); goto err; } rv = zebra_get_bank(f,&ftxa,ftp.links[KFTX_FTXA-1]); if (rv) { sprintf(zdab_err, "error getting FTXA bank: %s", zebra_err); goto err; } if (ftxa.links[KFTXA_FTXK-1] == 0) { sprintf(zdab_err, "FTXK link is zero!"); goto err; } rv = zebra_get_bank(f,&ftxk,ftxa.links[KFTXA_FTXK-1]); if (rv) { sprintf(zdab_err, "error getting FTXK bank: %s", zebra_err); goto err; } unpack_ftxk(ftxk.data, bftxk); return 0; err: return -1; } /* Get and unpack the RSP bank from the FTXR bank from the FTP fitter. * * Returns 0 if successful, or -1 on error. If there was an error, the error * string is printed to zdab_err. */ int get_rsp(zebraFile *f, zebraBank *ev, RSPBank *brsp) { int rv; zebraBank ft, ftp, ftxa, ftxr; if (ev->links[KEV_FT-1] == 0) { sprintf(zdab_err, "FT link is zero!"); goto err; } rv = zebra_get_bank(f,&ft,ev->links[KEV_FT-1]); if (rv) { sprintf(zdab_err, "error getting FT bank: %s", zebra_err); goto err; } if (ft.links[KFT_FTP-1] == 0) { sprintf(zdab_err, "FTP link is zero!"); goto err; } rv = zebra_get_bank(f,&ftp,ft.links[KFT_FTP-1]); if (rv) { sprintf(zdab_err, "error getting FTP bank: %s", zebra_err); goto err; } if (ftp.links[KFTX_FTXA-1] == 0) { sprintf(zdab_err, "FTXA link is zero!"); goto err; } rv = zebra_get_bank(f,&ftxa,ftp.links[KFTX_FTXA-1]); if (rv) { sprintf(zdab_err, "error getting FTXA bank: %s", zebra_err); goto err; } if (ftxa.links[KFTXA_FTXR-1] == 0) { sprintf(zdab_err, "FTXR link is zero!"); goto err; } rv = zebra_get_bank(f,&ftxr,ftxa.links[KFTXA_FTXR-1]); if (rv) { sprintf(zdab_err, "error getting FTXR bank: %s", zebra_err); goto err; } unpack_rsp(ftxr.data, brsp); return 0; err: return -1; } void unpack_rsp(uint32_t *data, RSPBank *b) { unpack((uint8_t *) data, "f", &b->optical_response); unpack((uint8_t *) (data+1), "f", &b->nwin); unpack((uint8_t *) (data+2), "f", &b->nwin2); unpack((uint8_t *) (data+3), "f", &b->ndark); unpack((uint8_t *) (data+4), "f", &b->neff); unpack((uint8_t *) (data+5), "f", &b->ncor); unpack((uint8_t *) (data+6), "f", &b->ncormc); unpack((uint8_t *) (data+7), "f", &b->nonline); unpack((uint8_t *) (data+8), "f", &b->ncal); unpack((uint8_t *) (data+9), "f", &b->nefficient); unpack((uint8_t *) (data+10), "f", &b->nworking); unpack((uint8_t *) (data+11), "f", &b->ene); unpack((uint8_t *) (data+12), "f", &b->uncertainty); unpack((uint8_t *) (data+13), "f", &b->quality); unpack((uint8_t *) (data+14), "f", &b->r_d2o); unpack((uint8_t *) (data+15), "f", &b->r_acr); unpack((uint8_t *) (data+16), "f", &b->r_h2o); unpack((uint8_t *) (data+17), "f", &b->r_fresnel); unpack((uint8_t *) (data+18), "f", &b->r_mpe); unpack((uint8_t *) (data+19), "f", &b->r_pmtr); unpack((uint8_t *) (data+20), "f", &b->r_eff); unpack((uint8_t *) (data+21), "f", &b->drift); unpack((uint8_t *) (data+22), "f", &b->nhits); unpack((uint8_t *) (data+23), "l", &b->fit_idx); unpack((uint8_t *) (data+24), "f", &b->nwin_allq); unpack((uint8_t *) (data+25), "f", &b->nhits_allq); unpack((uint8_t *) (data+26), "f", &b->nhits_dqxx); unpack((uint8_t *) (data+27), "f", &b->nwin_pt); unpack((uint8_t *) (data+28), "f", &b->tshift); unpack((uint8_t *) (data+29), "f", &b->pmt_response); unpack((uint8_t *) (data+30), "f", &b->alt_energy); unpack((uint8_t *) (data+31), "f", &b->nckv); unpack((uint8_t *) (data+32), "f", &b->resolution); unpack((uint8_t *) (data+33), "f", &b->fom); unpack((uint8_t *) (data+34), "f", &b->ncd_shad_cor); unpack((uint8_t *) (data+35), "f", &b->rlambda); unpack((uint8_t *) (data+36), "f", &b->omega); unpack((uint8_t *) (data+37), "f", &b->ckvprob); unpack((uint8_t *) (data+38), "f", &b->chaneff); unpack((uint8_t *) (data+39), "f", &b->pmteff); unpack((uint8_t *) (data+40), "f", &b->mpe); unpack((uint8_t *) (data+41), "f", &b->spare1); unpack((uint8_t *) (data+42), "f", &b->spare2); unpack((uint8_t *) (data+43), "f", &b->spare3); unpack((uint8_t *) (data+44), "f", &b->spare4); unpack((uint8_t *) (data+45), "f", &b->spare5); unpack((uint8_t *) (data+46), "f", &b->spare6); unpack((uint8_t *) (data+47), "f", &b->spare7); unpack((uint8_t *) (data+48), "f", &b->spare8); unpack((uint8_t *) (data+49), "f", &b->spare9); } void unpack_ftpt(uint32_t *data, FTPTBank *b) { unpack((uint8_t *) data, "f",&b->u); unpack((uint8_t *) (data+1), "f",&b->v); unpack((uint8_t *) (data+2), "f",&b->w); unpack((uint8_t *) (data+3), "f",&b->du); unpack((uint8_t *) (data+4), "f",&b->dv); unpack((uint8_t *) (data+5), "f",&b->dw); } void unpack_ftpv(uint32_t *data, FTPVBank *b) { unpack((uint8_t *) data, "f",&b->x); unpack((uint8_t *) (data+1), "f",&b->y); unpack((uint8_t *) (data+2), "f",&b->z); unpack((uint8_t *) (data+3), "f",&b->t); unpack((uint8_t *) (data+4), "f",&b->dx); unpack((uint8_t *) (data+5), "f",&b->dy); unpack((uint8_t *) (data+6), "f",&b->dz); unpack((uint8_t *) (data+7), "f",&b->dt); } void unpack_ftxk(uint32_t *data, FTXKBank *b) { unpack((uint8_t *) data, "f",&b->prob); unpack((uint8_t *) (data+1), "f",&b->energy); unpack((uint8_t *) (data+2), "f",&b->ene_merr); unpack((uint8_t *) (data+3), "f",&b->ene_perr); unpack((uint8_t *) (data+4), "f",&b->neff); unpack((uint8_t *) (data+5), "f",&b->dir_scale); unpack((uint8_t *) (data+6), "f",&b->dir_scale_sq); unpack((uint8_t *) (data+7), "f",&b->scat_scale); unpack((uint8_t *) (data+8), "f",&b->refl_scale); unpack((uint8_t *) (data+9), "f",&b->refl_av1_scale); unpack((uint8_t *) (data+10), "f",&b->refl_av2_scale); unpack((uint8_t *) (data+11), "f",&b->refl_ncd_scale); unpack((uint8_t *) (data+12), "f",&b->spare1); unpack((uint8_t *) (data+13), "f",&b->spare2); unpack((uint8_t *) (data+14), "f",&b->spare3); unpack((uint8_t *) (data+15), "f",&b->spare4); unpack((uint8_t *) (data+16), "f",&b->spare5); } void unpack_ftk(uint32_t *data, FTKBank *b) { unpack((uint8_t *) data, "l",&b->method); unpack((uint8_t *) (data+1), "l",&b->retc); unpack((uint8_t *) (data+2), "l",&b->method); unpack((uint8_t *) (data+3), "l",&b->retc); unpack((uint8_t *) (data+4), "l",&b->pmt_avail); unpack((uint8_t *) (data+5), "l",&b->pmt_used); unpack((uint8_t *) (data+6), "l",&b->early); unpack((uint8_t *) (data+7), "l",&b->late); unpack((uint8_t *) (data+8), "l",&b->iter); unpack((uint8_t *) (data+9), "f",&b->prob); unpack((uint8_t *) (data+10), "f",&b->energy); unpack((uint8_t *) (data+11), "f",&b->ene_merr); unpack((uint8_t *) (data+12), "f",&b->ene_perr); unpack((uint8_t *) (data+13), "f",&b->neff); unpack((uint8_t *) (data+14), "f",&b->dir_scale); unpack((uint8_t *) (data+15), "f",&b->dir_scale_sq); unpack((uint8_t *) (data+16), "f",&b->scat_scale); unpack((uint8_t *) (data+17), "f",&b->refl_scale); unpack((uint8_t *) (data+18), "f",&b->refl_av1_scale); unpack((uint8_t *) (data+19), "f",&b->refl_av2_scale); unpack((uint8_t *) (data+20), "f",&b->refl_ncd_scale); unpack((uint8_t *) (data+21), "f",&b->spare1); unpack((uint8_t *) (data+22), "f",&b->spare2); unpack((uint8_t *) (data+23), "f",&b->spare3); unpack((uint8_t *) (data+24), "f",&b->spare4); unpack((uint8_t *) (data+25), "f",&b->spare5); } void unpack_mc(uint32_t *data, MCBank *b) { unpack((uint8_t *) data, "l",&b->jdy); unpack((uint8_t *) (data+1), "l",&b->ut1); unpack((uint8_t *) (data+2), "l",&b->ut2); unpack((uint8_t *) (data+3), "l",&b->dte); unpack((uint8_t *) (data+4), "l",&b->hmsc); unpack((uint8_t *) (data+5), "l",&b->seed1); unpack((uint8_t *) (data+6), "l",&b->seed2); unpack((uint8_t *) (data+7), "l",&b->seed_num); unpack((uint8_t *) (data+8), "l",&b->dtp); unpack((uint8_t *) (data+9), "f",&b->mcver); unpack((uint8_t *) (data+10), "l",&b->evn); unpack((uint8_t *) (data+11), "F",&b->gtr); unpack((uint8_t *) (data+13), "l",&b->num_ge_err); unpack((uint8_t *) (data+14), "f",&b->pmt_eff); } void unpack_mcgn(uint32_t *data, MCGNBank *b) { unpack((uint8_t *) data, "l",&b->id); unpack((uint8_t *) (data+1), "l",&b->num); unpack((uint8_t *) (data+2), "l",&b->radcor_proc); unpack((uint8_t *) (data+3), "l",&b->radcor_made_gamma); unpack((uint8_t *) (data+4), "l",&b->spare5); unpack((uint8_t *) (data+5), "l",&b->spare6); unpack((uint8_t *) (data+7), "l",&b->spare7); unpack((uint8_t *) (data+8), "l",&b->spare8); unpack((uint8_t *) (data+9), "l",&b->spare9); unpack((uint8_t *) (data+10), "l",&b->spare10); unpack((uint8_t *) (data+12), "f",&b->radcor_xtot); unpack((uint8_t *) (data+13), "f",&b->radcor_xdif); unpack((uint8_t *) (data+14), "f",&b->gentim_xpar); unpack((uint8_t *) (data+15), "f",&b->spare14); unpack((uint8_t *) (data+16), "f",&b->spare15); unpack((uint8_t *) (data+17), "f",&b->spare16); unpack((uint8_t *) (data+18), "f",&b->spare17); unpack((uint8_t *) (data+19), "f",&b->spare18); unpack((uint8_t *) (data+20), "f",&b->spare19); unpack((uint8_t *) (data+21), "f",&b->spare20); } void unpack_mcvx(uint32_t *data, MCVXBank *b) { unpack((uint8_t *) data, "l",&b->cls); unpack((uint8_t *) (data+1), "l",&b->inc); unpack((uint8_t *) (data+2), "f",&b->x); unpack((uint8_t *) (data+3), "f",&b->y); unpack((uint8_t *) (data+4), "f",&b->z); unpack((uint8_t *) (data+5), "F",&b->tim); unpack((uint8_t *) (data+7), "l",&b->rgn); unpack((uint8_t *) (data+8), "l",&b->idm); unpack((uint8_t *) (data+9), "l",&b->rg2); unpack((uint8_t *) (data+10), "l",&b->im2); unpack((uint8_t *) (data+12), "f",&b->bnx); unpack((uint8_t *) (data+13), "f",&b->bny); unpack((uint8_t *) (data+14), "f",&b->bnz); unpack((uint8_t *) (data+15), "l",&b->cer); } void unpack_mctk(uint32_t *data, MCTKBank *b) { unpack((uint8_t *) data, "l",&b->idp); unpack((uint8_t *) (data+1), "f",&b->drx); unpack((uint8_t *) (data+2), "f",&b->dry); unpack((uint8_t *) (data+3), "f",&b->drz); unpack((uint8_t *) (data+4), "f",&b->ene); unpack((uint8_t *) (data+5), "l",&b->rgn); unpack((uint8_t *) (data+6), "l",&b->idm); unpack((uint8_t *) (data+7), "f",&b->plx); unpack((uint8_t *) (data+8), "f",&b->ply); unpack((uint8_t *) (data+9), "f",&b->plz); unpack((uint8_t *) (data+10), "f",&b->stp); unpack((uint8_t *) (data+11), "f",&b->near); } void unpack_ev(uint32_t *data, EVBank *b) { unpack((uint8_t *) data, "l",&b->run); unpack((uint8_t *) (data+1), "l",&b->evn); unpack((uint8_t *) (data+2), "l",&b->dtp); unpack((uint8_t *) (data+3), "l",&b->jdy); unpack((uint8_t *) (data+4), "l",&b->ut1); unpack((uint8_t *) (data+5), "l",&b->ut2); unpack((uint8_t *) (data+6), "l",&b->dte); unpack((uint8_t *) (data+7), "l",&b->hmsc); unpack((uint8_t *) (data+8), "F",&b->gtr); unpack((uint8_t *) (data+10),"l",&b->npm); unpack((uint8_t *) (data+11),"f",&b->nph); unpack((uint8_t *) (data+12),"l",&b->sub_run); unpack((uint8_t *) (data+13),"l",&b->mc_pck); unpack((uint8_t *) (data+14),"l",&b->rec); unpack((uint8_t *) (data+15),"l",&b->vpck); unpack((uint8_t *) (data+16),"l",&b->gtr_id); unpack((uint8_t *) (data+17),"l",&b->trg_type); unpack((uint8_t *) (data+18),"l",&b->peak); unpack((uint8_t *) (data+19),"l",&b->diff); unpack((uint8_t *) (data+20),"l",&b->integral); unpack((uint8_t *) (data+21),"l",&b->err); unpack((uint8_t *) (data+22),"l",&b->data_set); unpack((uint8_t *) (data+22),"lll",&b->spare1[0], &b->spare1[1], &b->spare1[2]); unpack((uint8_t *) (data+26),"l",&b->ncd_status); unpack((uint8_t *) (data+27),"l",&b->num_muxg); unpack((uint8_t *) (data+29),"l",&b->num_mux); unpack((uint8_t *) (data+29),"l",&b->num_scope); unpack((uint8_t *) (data+30),"lllll",&b->spare2[0], &b->spare2[1], &b->spare2[2], &b->spare2[3], &b->spare2[4]); unpack((uint8_t *) (data+35),"l",&b->ncd_clk_up); unpack((uint8_t *) (data+36),"l",&b->ncd_clk_lw); unpack((uint8_t *) (data+37),"l",&b->ncd_reg); unpack((uint8_t *) (data+38),"l",&b->ncd_gtid); unpack((uint8_t *) (data+39),"l",&b->ncd_sync); unpack((uint8_t *) (data+40),"llllllllll",&b->spare3[0], &b->spare3[1], &b->spare3[2], &b->spare3[3], &b->spare3[4], &b->spare3[5], &b->spare3[6], &b->spare3[7], &b->spare3[8], &b->spare3[9]); } void unpack_pmt(uint32_t *data, PMTBank *b) { unpack((uint8_t *) data,"l",&b->pn); unpack((uint8_t *) (data+1),"l",&b->pf); unpack((uint8_t *) (data+2),"f",&b->pt); unpack((uint8_t *) (data+3),"f",&b->phl); unpack((uint8_t *) (data+4),"f",&b->phs); unpack((uint8_t *) (data+5),"f",&b->plx); unpack((uint8_t *) (data+6),"f",&b->pt0); unpack((uint8_t *) (data+7),"l",&b->pif); unpack((uint8_t *) (data+8),"f",&b->pit); unpack((uint8_t *) (data+9),"f",&b->pihl); unpack((uint8_t *) (data+10),"f",&b->pihs); unpack((uint8_t *) (data+11),"f",&b->pilx); unpack((uint8_t *) (data+12),"f",&b->pit0); unpack((uint8_t *) (data+13),"l",&b->cell); unpack((uint8_t *) (data+14),"l",&b->pin); unpack((uint8_t *) (data+15),"f",&b->tslh); unpack((uint8_t *) (data+16),"f",&b->hca); unpack((uint8_t *) (data+17),"l",&b->eca_val); unpack((uint8_t *) (data+18),"l",&b->pca_val); unpack((uint8_t *) (data+19),"l",&b->anxx); unpack((uint8_t *) (data+20),"f",&b->ept); unpack((uint8_t *) (data+21),"f",&b->ehl); unpack((uint8_t *) (data+22),"f",&b->ehs); unpack((uint8_t *) (data+23),"f",&b->elx); unpack((uint8_t *) (data+24),"f",&b->pt1); unpack((uint8_t *) (data+25),"f",&b->ptm); unpack((uint8_t *) (data+26),"f",&b->ptms); unpack((uint8_t *) (data+27),"f",&b->qm); unpack((uint8_t *) (data+28),"l",&b->qms); unpack((uint8_t *) (data+29),"f",&b->qrc); } int swap_PmtRecord(aPmtEventRecord *aPmtRecord, size_t size) { /* Swap a Pmt Event Record. This function swaps both the Pmt event record * and the PMT hits and sub fields. Returns -1 if the PMT record has too * many hits. */ SWAP_INT32(aPmtRecord, sizeof(aPmtEventRecord)/sizeof(uint32_t)); int npmt = aPmtRecord->NPmtHit; if (npmt > MAX_NHIT) { fprintf(stderr, "Read error: Bad ZDAB -- %d pmt hit!", npmt); return -1; } else { if (size < sizeof(aPmtEventRecord) + 3*npmt*4) { fprintf(stderr, "swap_PmtRecord: size of record is %zu bytes, but there are %i PMT hits", size, npmt); return -1; } // swap the hit data SWAP_INT32(aPmtRecord + 1, 3*npmt); // swap the sub-fields uint32_t *sub_header = &aPmtRecord->CalPckType; while (*sub_header & SUB_NOT_LAST) { if (size < (sub_header - (uint32_t *) aPmtRecord)*4 + (*sub_header & SUB_LENGTH_MASK)*4 + 4) { fprintf(stderr, "swap_PmtRecord: size of record is %zu bytes, " "but sub-field requires %lu bytes", size, (sub_header - (uint32_t *) aPmtRecord)*4 + (*sub_header & SUB_LENGTH_MASK)*4 + 4); return -1; } sub_header += (*sub_header & SUB_LENGTH_MASK); SWAP_INT32(sub_header, 1); // swap the sub-field header // get number of data words (-1 because we don't want to include header size) uint32_t data_words = (*sub_header & SUB_LENGTH_MASK) - 1; if (size < (sub_header - (uint32_t *) aPmtRecord)*4 + (*sub_header & SUB_LENGTH_MASK)*4) { fprintf(stderr, "swap_PmtRecord: size of record is %zu bytes, " "but sub-field requires %lu bytes", size, (sub_header - (uint32_t *) aPmtRecord)*4 + (*sub_header & SUB_LENGTH_MASK)*4); return -1; } SWAP_INT32(sub_header+1, data_words); } } return 0; } void swap_TrigRecord(struct TriggerInfo *aTrigRecord) { /* Byte swap a Trigger Record. */ SWAP_INT32(aTrigRecord, sizeof(struct TriggerInfo)/sizeof(uint32_t)); } void swap_RunRecord(struct RunRecord *aRunRecord) { /* Byte swap a Run Record. */ SWAP_INT32(aRunRecord, sizeof(struct RunRecord)/sizeof(uint32_t)); }