import os from collections import Counter import matplotlib.pyplot as plt import numpy as np import pandas as pd def linesplit(line): """ Splits line of file into useful components. Returns (dm, pulse width, originating filename). """ dm, line = line.split("pc/cc") dm = int(dm) pw, fname = line.split(" s ") pw = float(pw) fname = fname.strip().removesuffix("_injected") return (dm, pw, fname) def updateDic(lines, dic): """ Processes a list of lines and adds them to given dictionary in-place. """ for line in lines: dm, pw, fname = linesplit(line) dic["file"].append(fname) dic["dm"].append(dm) dic["pulseWidth"].append(pw) injectedDic = { "file" : [], "dm" : [], "pulseWidth" : [] } detectedDic = { "file" : [], "dm" : [], "pulseWidth" : [] } #load injected data into dataframe with open(os.path.join(".","out","2025-07-31T17-25-54.txt"), "r") as file: lines = file.readlines() updateDic(lines, injectedDic) injections = pd.DataFrame(data=injectedDic) #this is our main object for injection data #load detection data into dataframe with open(os.path.join(".","out","plotOut.txt"), "r") as file: lines = file.readlines() updateDic(lines, detectedDic) detections = pd.DataFrame(data=detectedDic) #this is our main object for detection data #define summary printing for multiple steps def summary(stage): print(f"Summary Stage {stage}") print(f"Number of files injected: {len(Counter(injections['file']))}") print(f"Number of files with detections: {len(Counter(detections['file']))}") print("=========================") print(f"Number of pulses injected: {len(injections['dm'])}") print(f"Number of pulses detected: {len(detections['dm'])}") print("=========================") print(f"File ratio: {round(len(Counter(detections['file']))/len(Counter(injections['file'])), 3)}") print(f"Detection ratio: {round(len(detections['dm'])/len(injections['dm']), 3)}") print("=========================") #print initial summary summary(1) #many files contained pulsar bursts, so we filter those out via DM minDM = (10**2.5) * 0.95 #as per signal generation, plus a bit of wiggle room print(f"Filtering out pulsars (DM below {int(minDM)}...)") detections = detections[detections['dm'] > minDM] summary(2) #Let's do detection matching! Yaaaay! #What detections line up to which injections? This will determine which ones got missed entirely. #Define some kind of epsilon for DM and pulse width; if detection is within epsilon in both DM and PW we can match it. dmEps = 0.05 pwEps = 0.2 #and define an auxiliary array of bools for injections containing the "is matched?" information. isMatched = [False] * len(injections['dm'])