diff --git a/km3buu/output.py b/km3buu/output.py index 8d372bfb5c8588557a402d0e8df201f585e781b1..2843e8fbb4cc174196e625d97330e7f24ed294b8 100644 --- a/km3buu/output.py +++ b/km3buu/output.py @@ -608,6 +608,7 @@ class GiBUUOutput: def write_detector_file(gibuu_output, ofile="gibuu.offline.root", + no_files=1, geometry=CanVolume(), livetime=3.156e7, propagate_tau=True): # pragma: no cover @@ -620,6 +621,8 @@ def write_detector_file(gibuu_output, Output object which wraps the information from the GiBUU output files ofile: str Output filename + no_files: int (default: 1) + Number of output files written geometry: DetectorVolume The detector geometry which should be used livetime: float @@ -628,12 +631,6 @@ def write_detector_file(gibuu_output, if not isinstance(geometry, DetectorVolume): raise TypeError("Geometry needs to be a DetectorVolume") - evt = ROOT.Evt() - outfile = ROOT.TFile.Open(ofile, "RECREATE") - tree = ROOT.TTree("E", "KM3NeT Evt Tree") - tree.Branch("Evt", evt, 32000, 4) - mc_trk_id = 0 - def add_particles(particle_data, pos_offset, rotation, start_mc_trk_id, timestamp, status): nonlocal evt @@ -678,6 +675,10 @@ def write_detector_file(gibuu_output, sec_lep_type *= -1 event_data = gibuu_output.arrays + + if no_files > len(event_data): + raise IndexError("More files to write than contained events!") + bjorkenx = event_data.Bx bjorkeny = event_data.By @@ -696,6 +697,7 @@ def write_detector_file(gibuu_output, w2 = gibuu_output.w2weights(geometry.volume, targets_per_volume, 4 * np.pi) global_generation_weight = gibuu_output.global_generation_weight(4 * np.pi) + mean_xsec_func = gibuu_output.mean_xsec head = ROOT.Head() header_dct = EMPTY_KM3NET_HEADER_DICT.copy() @@ -714,95 +716,113 @@ def write_detector_file(gibuu_output, version, timestamp.strftime("%Y%m%d %H%M%S")) header_dct["primary"] = "{:d}".format(nu_type) - for k, v in header_dct.items(): - head.set_line(k, v) - head.Write("Head") - - mean_xsec_func = gibuu_output.mean_xsec - - for mc_event_id, event in enumerate(event_data): - evt.clear() - evt.id = mc_event_id - evt.mc_run_id = mc_event_id - # Weights - evt.w.push_back(geometry.volume) #w1 (can volume) - evt.w.push_back(w2[mc_event_id]) #w2 - evt.w.push_back(-1.0) #w3 (= w2*flux) - # Event Information (w2list) - evt.w2list.resize(W2LIST_LENGTH) - evt.w2list[W2LIST_LOOKUP["PS"]] = global_generation_weight - evt.w2list[W2LIST_LOOKUP["EG"]] = gibuu_output.flux_index - evt.w2list[W2LIST_LOOKUP["XSEC_MEAN"]] = mean_xsec_func(event.lepIn_E) - evt.w2list[W2LIST_LOOKUP["XSEC"]] = event.xsec - evt.w2list[W2LIST_LOOKUP["TARGETA"]] = gibuu_output.A - evt.w2list[W2LIST_LOOKUP["TARGETZ"]] = gibuu_output.Z - evt.w2list[W2LIST_LOOKUP["BX"]] = bjorkenx[mc_event_id] - evt.w2list[W2LIST_LOOKUP["BY"]] = bjorkeny[mc_event_id] - evt.w2list[W2LIST_LOOKUP["CC"]] = ichan - evt.w2list[W2LIST_LOOKUP["ICHAN"]] = SCATTERING_TYPE_TO_GENIE[ - event.evType] - evt.w2list[W2LIST_LOOKUP["VERINCAN"]] = 1 - evt.w2list[W2LIST_LOOKUP["LEPINCAN"]] = 1 - evt.w2list[W2LIST_LOOKUP["GIBUU_WEIGHT"]] = event.weight - evt.w2list[W2LIST_LOOKUP["GIBUU_SCAT_TYPE"]] = event.evType - #TODO - evt.w2list[W2LIST_LOOKUP["DXSEC"]] = np.nan - evt.w2list[W2LIST_LOOKUP["COLUMN_DEPTH"]] = np.nan - evt.w2list[W2LIST_LOOKUP["P_EARTH"]] = np.nan - evt.w2list[W2LIST_LOOKUP["WATER_INT_LEN"]] = np.nan - - # Vertex Position - vtx_pos = np.array(geometry.random_pos()) - # Direction - phi = np.random.uniform(0, 2 * np.pi) - cos_theta = np.random.uniform(-1, 1) - sin_theta = np.sqrt(1 - cos_theta**2) - - dir_x = np.cos(phi) * sin_theta - dir_y = np.sin(phi) * sin_theta - dir_z = cos_theta - - direction = np.array([dir_x, dir_y, dir_z]) - theta = np.arccos(cos_theta) - R = Rotation.from_euler("yz", [theta, phi]) - - timestamp = np.random.uniform(0, livetime) - - nu_in_trk = ROOT.Trk() - nu_in_trk.id = mc_trk_id - mc_trk_id += 1 - nu_in_trk.mother_id = -1 - nu_in_trk.type = nu_type - nu_in_trk.pos.set(*vtx_pos) - nu_in_trk.dir.set(*direction) - nu_in_trk.E = event.lepIn_E - nu_in_trk.t = timestamp - nu_in_trk.status = PARTICLE_MC_STATUS["TRK_ST_PRIMARYNEUTRINO"] - evt.mc_trks.push_back(nu_in_trk) - - if tau_secondaries is not None: - event_tau_sec = tau_secondaries[mc_event_id] - add_particles(event_tau_sec, vtx_pos, R, mc_trk_id, timestamp, - PARTICLE_MC_STATUS["TRK_ST_FINALSTATE"]) - mc_trk_id += len(event_tau_sec.E) - else: - lep_out_trk = ROOT.Trk() - lep_out_trk.id = mc_trk_id + for i in range(no_files): + start_id = 0 + stop_id = len(event_data) + tmp_filename = ofile + if no_files > 1: + tmp_filename = ofile.replace(".root", ".{}.root".format(i + 1)) + bunch_size = stop_id // no_files + start_id = i * bunch_size + stop_id = (i + 1) * bunch_size if i < (no_files - 1) else stop_id + + evt = ROOT.Evt() + outfile = ROOT.TFile.Open(tmp_filename, "RECREATE") + tree = ROOT.TTree("E", "KM3NeT Evt Tree") + tree.Branch("Evt", evt, 32000, 4) + mc_trk_id = 0 + + for k, v in header_dct.items(): + head.set_line(k, v) + head.Write("Head") + + for mc_event_id, event in enumerate(event_data[start_id:stop_id]): + evt.clear() + evt.id = mc_event_id + evt.mc_run_id = mc_event_id + # Weights + evt.w.push_back(geometry.volume) #w1 (can volume) + evt.w.push_back(w2[mc_event_id]) #w2 + evt.w.push_back(-1.0) #w3 (= w2*flux) + # Event Information (w2list) + evt.w2list.resize(W2LIST_LENGTH) + evt.w2list[W2LIST_LOOKUP["PS"]] = global_generation_weight + evt.w2list[W2LIST_LOOKUP["EG"]] = gibuu_output.flux_index + evt.w2list[W2LIST_LOOKUP["XSEC_MEAN"]] = mean_xsec_func( + event.lepIn_E) + evt.w2list[W2LIST_LOOKUP["XSEC"]] = event.xsec + evt.w2list[W2LIST_LOOKUP["TARGETA"]] = gibuu_output.A + evt.w2list[W2LIST_LOOKUP["TARGETZ"]] = gibuu_output.Z + evt.w2list[W2LIST_LOOKUP["BX"]] = bjorkenx[mc_event_id] + evt.w2list[W2LIST_LOOKUP["BY"]] = bjorkeny[mc_event_id] + evt.w2list[W2LIST_LOOKUP["CC"]] = ichan + evt.w2list[W2LIST_LOOKUP["ICHAN"]] = SCATTERING_TYPE_TO_GENIE[ + event.evType] + evt.w2list[W2LIST_LOOKUP["VERINCAN"]] = 1 + evt.w2list[W2LIST_LOOKUP["LEPINCAN"]] = 1 + evt.w2list[W2LIST_LOOKUP["GIBUU_WEIGHT"]] = event.weight + evt.w2list[W2LIST_LOOKUP["GIBUU_SCAT_TYPE"]] = event.evType + #TODO + evt.w2list[W2LIST_LOOKUP["DXSEC"]] = np.nan + evt.w2list[W2LIST_LOOKUP["COLUMN_DEPTH"]] = np.nan + evt.w2list[W2LIST_LOOKUP["P_EARTH"]] = np.nan + evt.w2list[W2LIST_LOOKUP["WATER_INT_LEN"]] = np.nan + + # Vertex Position + vtx_pos = np.array(geometry.random_pos()) + # Direction + phi = np.random.uniform(0, 2 * np.pi) + cos_theta = np.random.uniform(-1, 1) + sin_theta = np.sqrt(1 - cos_theta**2) + + dir_x = np.cos(phi) * sin_theta + dir_y = np.sin(phi) * sin_theta + dir_z = cos_theta + + direction = np.array([dir_x, dir_y, dir_z]) + theta = np.arccos(cos_theta) + R = Rotation.from_euler("yz", [theta, phi]) + + timestamp = np.random.uniform(0, livetime) + + nu_in_trk = ROOT.Trk() + nu_in_trk.id = mc_trk_id mc_trk_id += 1 - lep_out_trk.mother_id = 0 - lep_out_trk.type = sec_lep_type - lep_out_trk.pos.set(*vtx_pos) - mom = np.array([event.lepOut_Px, event.lepOut_Py, event.lepOut_Pz]) - p_dir = R.apply(mom / np.linalg.norm(mom)) - lep_out_trk.dir.set(*p_dir) - lep_out_trk.E = event.lepOut_E - lep_out_trk.t = timestamp - lep_out_trk.status = PARTICLE_MC_STATUS["TRK_ST_FINALSTATE"] - evt.mc_trks.push_back(lep_out_trk) - - add_particles(event, vtx_pos, R, mc_trk_id, timestamp, - PARTICLE_MC_STATUS["TRK_ST_FINALSTATE"]) - tree.Fill() - outfile.Write() - outfile.Close() - del outfile + nu_in_trk.mother_id = -1 + nu_in_trk.type = nu_type + nu_in_trk.pos.set(*vtx_pos) + nu_in_trk.dir.set(*direction) + nu_in_trk.E = event.lepIn_E + nu_in_trk.t = timestamp + nu_in_trk.status = PARTICLE_MC_STATUS["TRK_ST_PRIMARYNEUTRINO"] + evt.mc_trks.push_back(nu_in_trk) + + if tau_secondaries is not None: + event_tau_sec = tau_secondaries[mc_event_id] + add_particles(event_tau_sec, vtx_pos, R, mc_trk_id, timestamp, + PARTICLE_MC_STATUS["TRK_ST_FINALSTATE"]) + mc_trk_id += len(event_tau_sec.E) + else: + lep_out_trk = ROOT.Trk() + lep_out_trk.id = mc_trk_id + mc_trk_id += 1 + lep_out_trk.mother_id = 0 + lep_out_trk.type = sec_lep_type + lep_out_trk.pos.set(*vtx_pos) + mom = np.array( + [event.lepOut_Px, event.lepOut_Py, event.lepOut_Pz]) + p_dir = R.apply(mom / np.linalg.norm(mom)) + lep_out_trk.dir.set(*p_dir) + lep_out_trk.E = event.lepOut_E + lep_out_trk.t = timestamp + lep_out_trk.status = PARTICLE_MC_STATUS["TRK_ST_FINALSTATE"] + evt.mc_trks.push_back(lep_out_trk) + + add_particles(event, vtx_pos, R, mc_trk_id, timestamp, + PARTICLE_MC_STATUS["TRK_ST_FINALSTATE"]) + tree.Fill() + outfile.Write() + outfile.Close() + del outfile + del evt + del tree