1414from rionid .io import (
1515 read_psdata ,
1616 handle_read_tdsm_bin ,
17- handle_read_tdsm ,
18- handle_read_rsa_specan_xml ,
19- handle_spectrumnpz_data ,
17+ handle_spectrumnpz_data , # probably I will just keep this option, delete the others
2018 handle_tiqnpz_data
2119)
2220from rionid .baseline import NONPARAMS_EST
@@ -72,11 +70,14 @@ def __init__(self, refion, alphap, filename=None, reload_data=None, circumferenc
7270 self .total_mass = dict ()
7371 self .yield_data = []
7472
75- self .ref_ion = refion
7673 self .highlight_ions = self ._parse_highlight_ions (highlight_ions )
7774 self .alphap = alphap
78- self .gammat = (1 / alphap )** 0.5 if alphap > 0 else 0
75+ self .gammat = 1.0 / (self .alphap ** 0.5 )
76+
7977 self .ring = Ring ('ESR' , circumference )
78+
79+ self .ref_ion = refion .strip ()
80+ self ._parse_ref_ion (refion )
8081
8182 # Physics / Matching Params
8283 self .peak_threshold_pct = float (peak_threshold_pct ) if peak_threshold_pct else 0.05
@@ -94,6 +95,7 @@ def __init__(self, refion, alphap, filename=None, reload_data=None, circumferenc
9495 self .match_count = 0
9596
9697 self .cache_file = self ._get_cache_file_path (filename ) if filename else None
98+ self .experimental_data = None
9799
98100 if filename is not None :
99101 if reload_data :
@@ -102,12 +104,66 @@ def __init__(self, refion, alphap, filename=None, reload_data=None, circumferenc
102104 else :
103105 try :
104106 self ._load_experimental_data ()
105- except FileNotFoundError :
107+ except ( FileNotFoundError , IOError ) :
106108 self ._get_experimental_data (filename )
107109
108- # Process peaks after loading
110+ # --- NEW DATA PROCESSING BLOCK ---
111+ if self .experimental_data is not None :
112+ freq , amp = self .experimental_data
113+
114+ # 1. Baseline Removal
115+ if remove_baseline :
116+ try :
117+ est = NONPARAMS_EST (amp )
118+ baseline = est .pls ('BrPLS' , l = psd_baseline_removed_l , ratio = 1e-6 )
119+ amp = amp - baseline
120+ except Exception as e :
121+ print (f"Baseline removal failed: { e } " )
122+ traceback .print_exc ()
123+
124+ # 2. Log-Safety (Clip negatives)
125+ # Ensure all values are > 0 for logarithmic plotting.
126+ # We use 1e-9 as a "floor" value.
127+ amp = np .maximum (amp , 1e-29 )
128+
129+ # 3. Normalization
130+ # Scale so the highest peak is 1.0
131+ max_val = np .max (amp )
132+ if max_val > 0 :
133+ amp = amp / max_val
134+
135+ # Update the stored data
136+ self .experimental_data = (freq , amp )
137+ # ---------------------------------
138+
139+ # Process peaks after loading and processing
109140 self .detect_peaks_and_widths ()
110141
142+ def _parse_ref_ion (self , refion ):
143+ # Regex to extract Mass(Digits), Element(Letters), Charge(Digits)
144+ # It handles both '98Zr+39' and '98Zr39+' inputs
145+ match = re .match (r'(\d+)([a-zA-Z]+).*?(\d+)' , self .ref_ion )
146+ if match :
147+ self .ref_aa = int (match .group (1 ))
148+ self .ref_el = match .group (2 )
149+ self .ref_charge = int (match .group (3 ))
150+ # Force standard format: 98Zr39+
151+ self .ref_ion = f"{ self .ref_aa } { self .ref_el } { self .ref_charge } +"
152+ else :
153+ # Fallback parsing
154+ try :
155+ # Try splitting by '+' if it exists in the middle
156+ if '+' in refion and not refion .endswith ('+' ):
157+ parts = refion .split ('+' )
158+ self .ref_charge = int (parts [1 ])
159+ self .ref_aa = int (re .split (r'(\d+)' , parts [0 ])[1 ])
160+ else :
161+ # Assume format like 98Zr39+
162+ self .ref_charge = int (re .findall (r'\d+' , refion )[- 1 ])
163+ self .ref_aa = int (re .findall (r'\d+' , refion )[0 ])
164+ except :
165+ print (f"Warning: Could not parse reference ion '{ refion } '." )
166+
111167 def _parse_highlight_ions (self , input_str ):
112168 """Parses a comma-separated string of ions into a list."""
113169 if not input_str : return []
@@ -128,15 +184,12 @@ def _get_experimental_data(self, filename):
128184 self .experimental_data = read_psdata (filename , dbm = False )
129185 elif ext in ['.bin_fre' , '.bin_time' , '.bin_amp' ]:
130186 self .experimental_data = handle_read_tdsm_bin (filename )
131- elif ext == '.tdms' :
132- self .experimental_data = handle_read_tdsm (filename )
133- elif ext in ['.xml' , '.specan' ]:
134- self .experimental_data = handle_read_rsa_specan_xml (filename )
135187 elif ext == '.npz' :
136- if 'spectrum' in base :
137- self .experimental_data = handle_spectrumnpz_data (filename , ** self .io_params )
138- else :
139- self .experimental_data = handle_tiqnpz_data (filename , ** self .io_params )
188+ self .experimental_data = handle_spectrumnpz_data (filename , ** self .io_params )
189+ #if 'spectrum' in base:
190+ # self.experimental_data = handle_spectrumnpz_data(filename, **self.io_params)
191+ #else:
192+ # self.experimental_data = handle_tiqnpz_data(filename, **self.io_params)
140193 elif ext == '.root' :
141194 raise ValueError ("ROOT files are not supported in this version. Please convert to NPZ/CSV." )
142195
@@ -166,7 +219,7 @@ def detect_peaks_and_widths(self):
166219 amp ,
167220 height = height_thresh ,
168221 distance = self .min_distance ,
169- prominence = height_thresh * 0.3 ,
222+ prominence = height_thresh * 0.2 ,
170223 width = 1
171224 )
172225
@@ -257,12 +310,12 @@ def _load_experimental_data(self):
257310 else :
258311 raise FileNotFoundError ("Cached data file not found. Please set reload_data to True to generate it." )
259312
260- def _set_particles_to_simulate_from_file (self , particles_to_simulate , verbose = None ):
313+ def _set_particles_to_simulate_from_file (self , particles_to_simulate ):
261314 """Parses the LISE++ output file."""
262315 self .ame = AMEData ()
263316 self .ame_data = self .ame .ame_table
264317 lise = LISEreader (particles_to_simulate )
265- self .particles_to_simulate = lise .get_info_all (verbose = verbose )
318+ self .particles_to_simulate = lise .get_info_all ()
266319
267320 def _calculate_moqs (self , particles = None ):
268321 """Calculates mass-to-charge ratios for all particles."""
@@ -299,7 +352,8 @@ def _calculate_srrf(self, fref=None, brho=None, ke=None, gam=None, correct=None)
299352 self .srrf = array ([1 - self .alphap * (self .moq [name ] - self .moq [self .ref_ion ]) / self .moq [self .ref_ion ]
300353 for name in self .moq ])
301354 if correct :
302- self .srrf = self .srrf + polyval (array (correct ), self .srrf * self .ref_frequency ) / self .ref_frequency
355+ correction = polyval (array (correct ), self .srrf * self .ref_frequency )
356+ self .srrf = self .srrf + correction / self .ref_frequency
303357
304358 def _simulated_data (self , brho = None , harmonics = None , mode = None , sim_scalingfactor = None , nions = None ):
305359 """Generates the final simulation dictionary for plotting."""
@@ -328,15 +382,15 @@ def _simulated_data(self, brho=None, harmonics=None, mode=None, sim_scalingfacto
328382
329383 self .nuclei_names = array (moq_keys )
330384 self .yield_data = np .array (self .yield_data , dtype = float )
385+ max_yield = np .max (self .yield_data )
386+ if max_yield > 0 :
387+ self .yield_data /= max_yield
388+
331389 if sim_scalingfactor :
332390 self .yield_data *= sim_scalingfactor
333391
334392 for harmonic in harmonics :
335- if mode == 'Frequency' :
336- harmonic_freq = self .srrf * self .ref_frequency
337- else :
338- harmonic_freq = self .srrf * self .ref_frequency * harmonic
339-
393+ harmonic_freq = self .srrf * self .ref_frequency * harmonic
340394 arr_stack = stack ((harmonic_freq , self .yield_data , self .nuclei_names ), axis = 1 )
341395 self .simulated_data_dict [f'{ harmonic } ' ] = arr_stack
342396
0 commit comments