def write_header(self, f): f.write('# smash and analysis version: %s %s\n' % \ (self.smash_version, sb.analysis_version_string())) f.write('# total number events: %d\n' % self.nevents) f.write('# pdg list:') for pdg in self.pdglist: f.write(' %d' % pdg) f.write('\n')
def plotting(data1, data2, config_file, smash_code_version, output_folder): quantities = data1.quantities.union(data2.quantities) pdglist = data1.pdglist.union(data2.pdglist) pdglist_abs = np.unique(np.abs(np.array(list(pdglist)))) colliding_systems = data1.colliding_systems.union(data2.colliding_systems) colliding_systems_list = list(colliding_systems) energies = sorted(list(data1.energies.union(data2.energies))) for quantity in quantities: if ('spectra' in quantity): continue collected_results_pp = [[], [], []] collected_results_AuAuPbPb = [[], [], []] for pdg_abs in pdglist_abs: # Sigma0 is added to Lambda plots if (pdg_abs == 3212): continue # We do not want the Deuteron plots to be displayed, because SMASH # needs to be modified for useful results (cross section cut off) if (pdg_abs == 1000010020): continue pdg_one_sort = [] if (pdg_abs in pdglist): pdg_one_sort.append(pdg_abs) if (-pdg_abs in pdglist): pdg_one_sort.append(-pdg_abs) for pdg in pdg_one_sort: for colliding_system in colliding_systems: if (pdg == pdg_abs): plot_format = '-' plot_label = colliding_system exp_fmt = 'o' else: plot_format = '--' plot_label = '' exp_fmt = 's' if (colliding_system == 'pp'): linewidth = 5 plot_color = 'midnightblue' else: linewidth = 5 plot_color = 'darkred' if data1.is_in_dict([quantity, colliding_system, pdg]): theory_vs_energy = data1.the_dict[quantity][ colliding_system][pdg] x, y = zip(*sorted(theory_vs_energy.iteritems())) plt.plot(x, y, plot_format, label=plot_label, color=plot_color, lw=linewidth) # store results in list to later save it for future comparison if (colliding_system == 'pp'): collected_results_pp[0].append(pdg) if (collected_results_pp[1] == []): collected_results_pp[1].append(x) collected_results_pp[2].append(y) if (colliding_system == 'AuAu/PbPb'): collected_results_AuAuPbPb[0].append(pdg) if (collected_results_AuAuPbPb[1] == []): collected_results_AuAuPbPb[1].append(x) collected_results_AuAuPbPb[2].append(y) if args.comp_prev_version: import comp_to_prev_version as cpv # read and plot results from previous version filename_prev = quantity + '_' + colliding_system.replace( '/', '') prev_SMASH_version = cpv.plot_previous_results( 'energy_scan', '', filename_prev + '.txt', plot_color=plot_color, pdg=pdg, plot_style=plot_format) if data2.is_in_dict([quantity, colliding_system, pdg]): exp_vs_energy = data2.the_dict[quantity][ colliding_system][pdg] x_exp, y_exp = zip(*sorted(exp_vs_energy.iteritems())) y_exp_values, y_exp_errors = zip(*y_exp) plt.errorbar(x_exp, y_exp_values, yerr = y_exp_errors, fmt = exp_fmt,\ color = plot_color, elinewidth = 2, markeredgewidth = 0) if args.comp_prev_version: #dummy, for combined legend entry of previous results. plt.plot(1, 0.0, linestyle='-', linewidth=10, zorder=1, alpha=0.2, color='dimgrey', label=prev_SMASH_version) plt.xlabel('$\sqrt{s_{NN}} [GeV]$') plt.xscale('log') if (quantity in ['total_multiplicity', 'midrapidity_yield']): if np.all(y == 0): print 'No positive values encountered in ' + str(quantity) + ' for ' + str(pdg) +\ '. Cannot log-scale the y axis, scale will be linear.' else: plt.yscale('log', nonposy='clip') hadron_name = sb.pdg_to_name(pdg_abs, config_file).decode("utf-8") antihadron_name = sb.pdg_to_name(-pdg_abs, config_file).decode("utf-8") plot_title = hadron_name if not pdg_abs in [111, 333]: # antiparticle of itself plot_title += ' (' + antihadron_name + ' dashed, squares)' title_dict = { 'total_multiplicity': ' $4\pi$ multiplicity', 'midrapidity_yield': ' $dN/dy|_{y = 0}$', 'meanmt0_midrapidity': ' $<m_{T}>|_{y = 0}$, $m_{T} = \sqrt{p_T^2 + m^2} - m$', 'meanpt_midrapidity': ' $<p_{T}>|_{y = 0}$' } plt.title(plot_title) plt.ylabel(title_dict[quantity]) plt.legend() plt.figtext(0.8, 0.94, " SMASH code: %s\n SMASH analysis: %s" % \ (smash_code_version, sb.analysis_version_string()), \ color = "gray", fontsize = 10) plt.savefig(output_folder + '/' + quantity + str(pdg_abs) + '.pdf') plt.clf() # Save results plotted above for future comparison filename_AuAuPbPb = quantity + '_' + 'AuAuPbPb' + '.txt' filename_pp = quantity + '_' + 'pp' + '.txt' store_results(output_folder + '/' + filename_AuAuPbPb, collected_results_AuAuPbPb, smash_code_version, quantity) store_results(output_folder + '/' + filename_pp, collected_results_pp, smash_code_version, quantity) # Plotting spectra, only those, where some data is present for quantity in quantities: if (quantity not in ['yspectra', 'mtspectra', 'ptspectra', 'v2spectra']): continue if (quantity == 'v2spectra' and not args.with_v2): continue for pdg in pdglist: if (abs(pdg) == 3212): continue if (abs(pdg) == 1000010020): continue collected_results_pp = [[], [], []] collected_results_AuAuPbPb = [[], [], []] for colliding_system in colliding_systems: #if not data2.is_in_dict([quantity, colliding_system, pdg]): continue #if not data1.is_in_dict([quantity, colliding_system, pdg]): continue # colors list for plotting col = cycle(colours) # to scale curves in mT and pT spectra by powers of 10 -> readability scaling_counter = -1 for element, energy in enumerate(energies): collider = determine_collider(energy) in_theory = data1.is_in_dict( [quantity, colliding_system, pdg, energy]) in_experiment = data2.is_in_dict( [quantity, colliding_system, pdg, energy]) #if (not in_experiment): continue if (in_experiment and not in_theory): print energy, colliding_system, pdg, in_theory, in_experiment, \ ': there is experimental data, but no SMASH calculation!' if (in_theory): plot_color = next(col) bin_edges, y = data1.the_dict[quantity][ colliding_system][pdg][energy] bin_edges = np.array(bin_edges) bin_width = bin_edges[1:] - bin_edges[:-1] x = 0.5 * (bin_edges[1:] + bin_edges[:-1]) y = np.array(y) # dN/dy if (quantity == 'yspectra'): y /= bin_width plt.plot(x, y, '-', lw=4, color=plot_color, label=str(energy)) # dN/dmT pole_masses = { 111: 0.138, 211: 0.138, 321: 0.495, 2212: 0.938, 3122: 1.116, 3312: 1.321, 3334: 1.672, 1000010020: 1.8756, 3212: 1.189 } m0 = pole_masses[abs(pdg)] if (quantity == 'mtspectra'): scaling_counter += 1 y /= ((x + m0) * bin_width) * ( 2.0 * data1.midrapidity_cut ) # factor 2 because [-y_cut; y_cut] if np.all( y == 0 ): # rescale y-axis to be linear if mtspectra of current energy are 0, but those plt.yscale( 'linear' ) # of the previous energy were not, so that the scale was already set to log scale. plt.plot(x, y * 10**scaling_counter, '-', lw=4, color=plot_color, label=str(energy) + r' $\times \ $10$^{\mathsf{' + str(scaling_counter) + r'}}$') # dN/dpT if (quantity == 'ptspectra'): scaling_counter += 1 y /= (bin_width * x) * ( 2.0 * data1.midrapidity_cut ) # factor 2 because [-y_cut; y_cut] if np.all( y == 0 ): # rescale y-axis to be linear if ptspectra of current energy are 0, but those plt.yscale( 'linear' ) # of the previous energy were not, so that the scale was already set to log scale. plt.plot(x, y * 10**scaling_counter, '-', lw=4, color=plot_color, label=str(energy) + r' $\times \ $10$^{\mathsf{' + str(scaling_counter) + r'}}$') # v2 if (quantity == 'v2spectra'): y /= (bin_width) * ( 2.0 * data1.midrapidity_cut ) # factor 2 because [-y_cut; y_cut] plt.plot(x, y, '-', lw=4, color=plot_color, label=str(energy)) # store results in list to later save for future comparison if (colliding_system == 'pp'): collected_results_pp[0].append(energy) if (collected_results_pp[1] == []): collected_results_pp[1].append(x) collected_results_pp[2].append(y) if (colliding_system == 'AuAu/PbPb'): collected_results_AuAuPbPb[0].append(energy) if (collected_results_AuAuPbPb[1] == []): collected_results_AuAuPbPb[1].append(x) collected_results_AuAuPbPb[2].append(y) # read and plot results from previous version if args.comp_prev_version and quantity != 'v2spectra': #v2 is not regularly run, old results are neither produced nor stored filename_prev = quantity + '_' + colliding_system.replace( '/', '') + '_' + str(pdg) prev_SMASH_version = cpv.plot_previous_results( 'energy_scan', '', filename_prev + '.txt', energy=energy, plot_color=plot_color, scaling_counter=scaling_counter) if (in_experiment): x, y, y_err = data2.the_dict[quantity][ colliding_system][pdg][energy] if (quantity == 'mtspectra'): plt.errorbar(x, y * 10**scaling_counter, yerr=y_err, fmt='o', color=plot_color) elif (quantity == 'ptspectra'): plt.errorbar(x, y * 10**scaling_counter, yerr=y_err, fmt='o', color=plot_color) elif (quantity == 'v2spectra'): plt.errorbar(x, y, yerr=y_err, fmt='o', color=plot_color) else: # yspectra plt.errorbar(x, y, yerr=y_err, fmt='o', color=plot_color) title_dict = { 'yspectra': '$dN/dy$', 'mtspectra': '$1/m_{T} \ d^2N/dm_{T} dy$ [GeV$^{-2}$]', 'ptspectra': '$1/p_{T} \ d^2N/dp_{T} dy$ [GeV$^{-2}$]', 'v2spectra': '$v_2$', } plot_title = sb.pdg_to_name(pdg, config_file).decode("utf-8") plot_title += ' in ' + colliding_system + ' collisions' plt.title(plot_title) plt.figtext(0.15, 0.94, " SMASH code: %s\n SMASH analysis: %s" % \ (smash_code_version, sb.analysis_version_string()), \ color = "gray", fontsize = 10) if (quantity == 'mtspectra' or quantity == 'ptspectra'): if np.all(y == 0): print 'No positive values encountered in ' + str(quantity) + ' for ' + str(pdg) +\ '. Cannot log-scale the y axis, scale will be linear.' else: plt.yscale('log', nonposy='clip') if (quantity == 'mtspectra'): plt.xlabel('$m_{T} - m_{0}$ [GeV]') else: plt.xlabel('$p_{T}$ [GeV]') elif (quantity == 'yspectra'): plt.xlabel('$y$') else: plt.xlabel('$p_{T}$ [GeV]') plt.ylabel(title_dict[quantity]) if (determine_collider(energy) != determine_collider( energies[(element + 1) % len(energies)])): if args.comp_prev_version: #dummy for legend entry of combined previous results. plt.plot(1, 0.0, linestyle='-', linewidth=10, zorder=1, color='dimgrey', label=prev_SMASH_version, alpha=0.2) plt.legend(loc='upper right', title='$\sqrt{s} \ $ [GeV] =', ncol=1, fontsize=26) plt.savefig(output_folder + '/' + quantity + '_' + colliding_system.replace('/', '') + '_' + str(determine_collider(energy)) + '_' + str(pdg) + '.pdf') plt.clf() plt.close() scaling_counter = -1 #re-initialize as generating a new plot # Save results plotted above for future comparison filename_AuAuPbPb = quantity + '_AuAuPbPb_' + str(pdg) + '.txt' filename_pp = quantity + '_pp_' + str(pdg) + '.txt' store_results(output_folder + '/' + filename_AuAuPbPb, collected_results_AuAuPbPb, smash_code_version, quantity) store_results(output_folder + '/' + filename_pp, collected_results_pp, smash_code_version, quantity)
ced.plot_angular_dist_data(args.exp_data, setup, pdg=[pdg1, pdg2]) ### (4b) plot data from previous SMASH versions if args.comp_prev_version: import comp_to_prev_version as cpv processes = [ 'total', 'N+N', 'N+N*', 'N+\xce\x94', 'N*+\xce\x94', 'N+\xce\x94*', '\xce\x94+\xce\x94', '\xce\x94+\xce\x94*' ] cpv.plot_previous_results('angular_distributions', setup, '/t.dat', color_list=colour_coding, process_list=processes) ### (5) set up axes, labels, etc plt.title( particle1.decode('utf8') + "+" + particle2.decode('utf8') + " @ $\sqrt{s}=" + str(round(np.sqrt(s), 2)) + "$ GeV") plt.xlabel("-t [$GeV^2$]") plt.ylabel("$d\sigma/dt$ [$mb/GeV^2$]") plt.yscale('log') plt.legend(title=smash_version, loc="best", fontsize=20, ncol=2) plt.figtext(0.8, 0.925, "SMASH analysis: %s" % \ (sb.analysis_version_string()), \ color = "gray", fontsize = 10) plt.tight_layout() plt.axvline(float(tmax), linestyle="--", color="black", linewidth=2) plt.savefig(output_file)
if (blocks_per_event == 0): blocks_per_event = res['blocks_per_event'] time = res['time'] smash_version = res['smash_version'] else: assert (blocks_per_event == res['blocks_per_event']) assert (smash_version == res['smash_version']) mul += res['mul'] mul_sqr += res['mul_sqr'] mul /= event_num # get average multiplicity mul_sqr /= event_num # get average square of multiplicity mul_err = np.sqrt((mul_sqr - mul * mul) / (event_num - 1)) with open(args.output_file, 'w') as f: f.write('# smash and analysis version\n') f.write('%s %s\n' % (smash_version, sb.analysis_version_string())) f.write('# total number events\n') f.write('%d\n' % event_num) f.write('# pdg codes list\n') for i in np.arange(total_pdgs): f.write('%d ' % pdg_list[i]) f.write('\n') f.write('# time moments array [%d]\n' % blocks_per_event) for i in np.arange(blocks_per_event): f.write('%.3f ' % time[i]) f.write('\n') for i in np.arange(total_pdgs): f.write( '# multiplicities and their stat errors of pdg %d versus time\n' % pdg_list[i]) for j in np.arange(blocks_per_event):
import smash_basic_scripts as sb import glob import yaml PathToData = sys.argv[1] Config = sys.argv[2] DataOutfile = sys.argv[3] with open(Config, 'r') as f: config_file = yaml.safe_load(f) TimeSteps = config_file['Output']['Output_Interval'] FinalTime = config_file['General']['End_Time'] Energy = config_file['Modi']['Collider']['E_Kin'] StartTime = -3 # fm TimeSteps = np.arange(StartTime, FinalTime, TimeSteps) smash_analysis_version = sb.analysis_version_string() setup = 'AuAu_central_cell' with open(PathToData + '/0/thermodynamics.dat') as f: smash_version = f.readline().split(' ')[1] NFolders = 10 dirs = np.arange(0, NFolders + 1) n_events = 0 dens_list = np.zeros(len(TimeSteps)) for dir in dirs: data_file = PathToData + '/{}/thermodynamics.dat'.format(dir) with open(data_file) as f: for rawline in f: line = rawline.split()
def print_to_file(self, out, tag, process_el=""): """Print data (process_list, process_count) to output file 'out'.""" process_list = sorted(self.process_list[tag]) # look for the possible elastic process and move it to the front if process_el: try: index_elast = process_list.index(process_el) process_list.pop(index_elast) process_list.insert(0, process_el) except IndexError: if self.args.verbose: print >> sout, "# Note: No elastic process found." except ValueError: if self.args.verbose: print >> sout, "# Note:", process_el, "(elastic process) is not in process list." print >> sout, "# Following processes were found:", for item in process_list: print >> sout, item, print >> sout # write initial state print >> out, "#initial", for pdg in self.initial_parts: print >> out, pdg, print >> out # write initial masses print >> out, "#masses", assert len(self.initial_masses) == 2 print >> out, ' '.join(str(mass) for mass in self.initial_masses) # write version print >> out, "#version", self.smashversion, "format", self.formatversion, \ "analysis", smash.analysis_version_string() # write labels print >> out, "#columns $\\sqrt{s}$[GeV] total total_err", if tag == 'process_type': for p_type in sorted(self.type_count.iterkeys()): print >> out, p_type, p_type + '_err', else: if process_el and (process_el not in process_list): print >> out, process_el, process_el + '_err', # elastic for proc in process_list: print >> out, proc, proc + '_err', print >> out # write cross sections and errors total_count = self.process_count['total'] if total_count > 0: total_xsection, total_xsection_err_sq = calc_tot_xs() #assert total_xsection_err_sq >= 0. total_xsection_rel_err_sq = total_xsection_err_sq / (total_count** 2) total_xsection_err = math.sqrt(total_xsection_err_sq) print >> out, self.energyindex, total_xsection, total_xsection_err, if tag == 'process_type': for p_type in sorted(self.type_count.iterkeys()): count = float(self.type_count[p_type]) xs = total_xsection * count / total_count excl_xsection_rel_err_sq = 1. / count if count else 0. error = xs * numpy.sqrt(total_xsection_rel_err_sq + excl_xsection_rel_err_sq) print >> out, xs, error, else: if process_el and (process_el not in process_list): count = float(self.process_count['elastic']) xs = total_xsection * count / total_count excl_xsection_rel_err_sq = 1. / count if count else 0. error = xs * numpy.sqrt(total_xsection_rel_err_sq + excl_xsection_rel_err_sq) print >> out, xs, error, for proc in process_list: count = float(self.process_count[(tag, proc)]) xs = total_xsection * count / total_count excl_xsection_rel_err_sq = 1. / count if count else 0. error = xs * numpy.sqrt(total_xsection_rel_err_sq + excl_xsection_rel_err_sq) print >> out, xs, error, if self.args.verbose: if total_xsection < 0.1: print >> sys.stderr, "Warning: low cross section encountered: energy: {}, cross section: {}".format( self.energyindex, total_xsection) print >> out
def plot(name, bin_factor, ch_list, style_dict, datafile="", cut_legend=""): n_ch = len(ch_list) # import hist_data with open("hist_" + name + ".txt") as df_smash: data = np.loadtxt(df_smash, delimiter=' ', unpack=True) bin_centers = data[0, :] hist = data[1:n_ch + 1, :] # make dN/dx plot bin_width = bin_centers[1] - bin_centers[0] hist_dx = hist[:] / bin_width # renormalize for data comparison (currently only mass spectra compared with data) if datafile != "": # do cross section plot for pp, data in mub if args.system == "pp" or args.system == "pNb": hist_dx = hist_dx * \ cross_sections_dict[args.system + args.energy] * 1000 # spectra for CC is normalized with averaged number of pions if args.system == "CC" or args.system == "ArKCl": hist_dx = hist_dx / normalization_AA() # rebin bin_centers_new, hist_new = rebin(bin_centers, hist_dx, n_ch, bin_factor) # plotting plt.plot(bin_centers_new, sum(hist_new), label="all", color='k', linewidth=3) for i in range(len(ch_list)): plt.plot(bin_centers_new, hist_new[i], style_dict["l_style"][i], label=ch_list[i], linewidth=2) # plot data if datafile != "": if 'mass' in name: data_path = os.path.join( args.data_dir + 'm_inv_spectrum_dileptons/' + args.system, datafile) elif 'pt' in name: data_path = os.path.join( args.data_dir + 'pT_spectrum/' + args.system + '/', datafile) elif 'y' in name: data_path = os.path.join( args.data_dir + 'y_spectrum/' + args.system + '/', datafile) else: print 'No experimental data found.' with open(data_path) as df: data = np.loadtxt(df, unpack=True) x_data = data[0, :] y_data = data[1, :] y_data_err = data[2, :] plt.errorbar(x_data, y_data, yerr=y_data_err, fmt='ro', ecolor='k', label="HADES", zorder=3) # write and read old results, only for total dN/dm spectra if name == "mass": # store dN/dm spectra for future comparison to previous version store_results("dN_dm_tot.txt", bin_centers_new, sum(hist_new), version()) if args.comp_prev_version: import comp_to_prev_version as cpv # plot reference data from previous SMASH version setup = str(args.system) + "_" + str( args.energy) + "_" + "filtered" cpv.plot_previous_results('dileptons', setup, '/dN_dm_tot.txt') # plot style leg = plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0, fancybox=True, title=args.system + "@" + args.energy + " GeV " + cut_legend) #plt.annotate(version(), xy=(0.02, 0.03), xycoords='axes fraction', bbox=dict(boxstyle="round", fc="w"), fontsize=12) plt.annotate('SMASH version: ' + version() + '\n' + 'Analysis suite version: ' + sb.analysis_version_string(), xy=(0.4, 0.92), xycoords='axes fraction', bbox=dict(boxstyle="round", fc="w"), fontsize=8) plt.xlim(style_dict["x_min"], style_dict["x_max"]) plt.ylim(style_dict["y_min"], style_dict["y_max"]) plt.xlabel(style_dict["xlab"]) plt.ylabel(style_dict["ylab"]) plt.yscale('log') plt.savefig("plot_" + name + ".pdf", bbox_extra_artists=(leg, ), bbox_inches='tight') plt.cla()
count_with_error = defaultdict(Average) # total count of processes with the initial pdgs pt_total = defaultdict(Average) # average transverse momentum nevent = 0 for rdir in os.listdir(path.abspath(datadir)): # loop over runs rdir = path.join(path.abspath(datadir), rdir) if path.isdir(rdir): #print rdir name = path.join(rdir, "particles_binary.bin") # if the argument is a file, read the contents if (path.isfile(name)): with smash.BinaryReader(name) as reader: # check the header for version information smashversion = reader.smash_version formatversion = reader.format_version if firstfile: print "#version", smashversion, "format", formatversion, "analysis", smash.analysis_version_string() firstfile = False # loop over all data blocks in the file for datablock in reader: if datablock['type'] == 'p': nevent += 1 # count particles and calculate transverse momentum pt_event = defaultdict(Average) count = defaultdict(int) for particle in datablock['part']: i = particle['pdgid'] if i not in pdglist_print: continue count[i] += 1 px = particle['p'][1] py = particle['p'][2]
def count_reactions_and_printout(binvar='Q2'): assert (binvar == 'Q2' or binvar == 't') parser = argparse.ArgumentParser() # options and arguments parser.add_argument("output_file", type=str) parser.add_argument("reactions_string", type=str) parser.add_argument("tstart", type=float) parser.add_argument("config_file", help="config file") parser.add_argument("files_to_analyze", nargs='+', help="binary file(s) containing collision history") args = parser.parse_args() with open(args.config_file, 'r') as f: d = yaml.load(f) if (args.reactions_string == "n_most_violating"): reactions, event_num, smash_version = count_reactions( args.files_to_analyze, args.tstart, binning_in=binvar) most_deviating_reactions = find_n_most_detbal_violating(reactions) print most_deviating_reactions reaction_names = [ tuple_to_name(x, args.config_file) for x in most_deviating_reactions ] else: reaction_names = args.reactions_string.split('|') only_count_reactions = [] for reaction_name in reaction_names: r = reaction_from_string(reaction_name, args.config_file) only_count_reactions.append(r) only_count_reactions.append(inv_reaction(r)) reactions, event_num, smash_version = count_reactions( args.files_to_analyze, args.tstart, only_count_reactions=only_count_reactions, binning_in=binvar) # Write output with open(args.output_file, 'w') as f: f.write('# smash and analysis version\n') f.write('%s %s\n' % (smash_version, sb.analysis_version_string())) f.write('# total number events\n') f.write('%d\n' % event_num) f.write('# total time\n') f.write('%.2f\n' % d['General']['End_Time']) f.write('# time to start counting reactions\n') f.write('%.2f\n' % args.tstart) f.write('# list of all reaction analyzed\n') f.write('%s\n' % '|'.join(reaction_names)) with open(args.output_file, 'a') as f: for rname in reaction_names: r = reaction_from_string(rname, args.config_file) binvar_name = {'Q2': 'M_inv', 't': '|t|'} f.write('# reaction - %s, %s bins, forward and backward\n' % (rname, binvar_name[binvar])) x = reactions[r].bin_centers() yf = reactions[r].hist yb = reactions[inv_reaction(r)].hist np.savetxt(f, x, fmt='%.3f', newline=' ') f.write('\n') np.savetxt(f, yf, fmt='%i', newline=' ') f.write('\n') np.savetxt(f, yb, fmt='%i', newline=' ') f.write('\n')