diff --git a/src/simpyson/converter.py b/src/simpyson/converter.py index 41ef4e1..f890b29 100644 --- a/src/simpyson/converter.py +++ b/src/simpyson/converter.py @@ -121,7 +121,7 @@ def hz2ppm(hz, b0, nucleus, isotope_file=None): isotope_file = os.path.join(dir, 'isotope_data.json') isotope = int(''.join(filter(str.isdigit, nucleus))) - element = ''.join(filter(str.isalpha, nucleus)).upper() + element = ''.join(filter(str.isalpha, nucleus)).capitalize() b0_unit = ''.join(filter(str.isalpha, b0)).lower() with open(isotope_file) as f: @@ -132,12 +132,16 @@ def hz2ppm(hz, b0, nucleus, isotope_file=None): raise ValueError(f'Nucleus {nucleus} not found in isotope data.') if b0_unit == 't': - b0_value = float(''.join(filter(str.isdigit, b0))) - ppm = hz / (b0_value * gamma) + b0_value = float(''.join(filter(lambda x: x.isdigit() or x == '.', b0))) + larm_freq = gamma * 1e7 * b0_value / (2 * np.pi * 1e6) + ppm = hz / np.abs(larm_freq) elif b0_unit == 'mhz': - b0_value = float(''.join(filter(str.isdigit, b0))) + b0_value = float(''.join(filter(lambda x: x.isdigit() or x == '.', b0))) gamma_h = data['H']['1']['Gamma'] - ppm = hz / (b0_value/(gamma_h/gamma)) + b0_value_T = 2 * np.pi * b0_value * 1e6 / (gamma_h * 1e7) + larm_freq = gamma * 1e7 * b0_value_T / (2 * np.pi * 1e6) + # ppm conversion requires absolute value of larm_freq + ppm = hz / np.abs(larm_freq) else: raise ValueError('B0 unit must be T or MHz.') @@ -165,7 +169,7 @@ def ppm2hz(ppm, b0, nucleus, isotope_file=None): isotope_file = os.path.join(dir, 'isotope_data.json') isotope = int(''.join(filter(str.isdigit, nucleus))) - element = ''.join(filter(str.isalpha, nucleus)).upper() + element = ''.join(filter(str.isalpha, nucleus)).capitalize() b0_unit = ''.join(filter(str.isalpha, b0)).lower() with open(isotope_file) as f: @@ -176,13 +180,16 @@ def ppm2hz(ppm, b0, nucleus, isotope_file=None): raise ValueError(f'Nucleus {nucleus} not found in isotope data.') if b0_unit == 't': - b0_value = float(''.join(filter(str.isdigit, b0))) - hz = ppm * (b0_value * gamma) + b0_value = float(''.join(filter(lambda x: x.isdigit() or x == '.', b0))) + larm_freq = gamma * 1e7 * b0_value / (2 * np.pi * 1e6) elif b0_unit == 'mhz': - b0_value = float(''.join(filter(str.isdigit, b0))) + b0_value = float(''.join(filter(lambda x: x.isdigit() or x == '.', b0))) gamma_h = data['H']['1']['Gamma'] - hz = ppm * (b0_value/(gamma_h/gamma)) + b0_value_T = 2 * np.pi * b0_value * 1e6 / (gamma_h * 1e7) + larm_freq = gamma * 1e7 * b0_value_T / (2 * np.pi * 1e6) else: raise ValueError('B0 unit must be T or MHz.') + hz = ppm * np.abs(larm_freq) + return hz \ No newline at end of file diff --git a/src/simpyson/gui.py b/src/simpyson/gui.py index c8bd5a4..ff89f36 100644 --- a/src/simpyson/gui.py +++ b/src/simpyson/gui.py @@ -120,6 +120,10 @@ def create_menu(self): convert_hz_to_ppm.triggered.connect(self.convert_hz_to_ppm) process_menu.addAction(convert_hz_to_ppm) + convert_ppm_to_hz = QAction('Convert ppm to Hz', self) + convert_ppm_to_hz.triggered.connect(self.convert_ppm_to_hz) + process_menu.addAction(convert_ppm_to_hz) + convert_fid_to_spe = QAction('Convert FID to SPE', self) convert_fid_to_spe.triggered.connect(self.convert_fid_to_spe) process_menu.addAction(convert_fid_to_spe) @@ -270,7 +274,7 @@ def convert_hz_to_ppm(self): file_name = item.text() file_data = self.files_data[file_name]['data'] - if file_data and 'hz' in file_data.data: # Remove the format check + if file_data and 'hz' in file_data.data: try: new_data = copy.deepcopy(file_data) new_data.b0 = b0 @@ -289,6 +293,50 @@ def convert_hz_to_ppm(self): self.plot_data(selected_items) + def convert_ppm_to_hz(self): + selected_items = self.file_list.selectedItems() + + if not selected_items: + QMessageBox.warning(self, 'Convert ppm to Hz', 'No file selected!') + return + + b0, ok_b0 = QInputDialog.getText(self, 'Input', 'Enter B0 (e.g., 400MHz or 9.4T):') + if not (ok_b0 and b0): + return + + nucleus, ok_nucleus = QInputDialog.getText(self, 'Input', 'Enter nucleus (e.g., 1H or 13C):') + if not (ok_nucleus and nucleus): + return + + for item in selected_items: + file_name = item.text() + file_data = self.files_data[file_name]['data'] + + if file_data and 'ppm' in file_data.data: + try: + new_data = copy.deepcopy(file_data) + new_data.b0 = b0 + new_data.nucleus = nucleus + + ppm = new_data.data['ppm'] + new_data.data['hz'] = ppm2hz(ppm, b0, nucleus) + + # This is just an initial implementation + # Maybe one should implement a way to select on the GUI + # which range to show on the plot + if 'ppm' in new_data.data: + del new_data.data['ppm'] + + self.files_data[file_name]['data'] = new_data + if file_name == self.current_file: + self.data = new_data + + except ValueError as e: + QMessageBox.warning(self, 'Convert ppm to Hz', + f"Error converting {file_name}: {str(e)}") + + self.plot_data(selected_items) + def convert_fid_to_spe(self): selected_items = self.file_list.selectedItems() diff --git a/src/simpyson/io.py b/src/simpyson/io.py index 1602c4c..b6498ae 100644 --- a/src/simpyson/io.py +++ b/src/simpyson/io.py @@ -72,7 +72,6 @@ def _read_spe(self): raise ValueError('Both B0 and nucleus must be specified.') else: dir = os.path.dirname(os.path.realpath(__file__)) - isotope_file = os.path.join(dir, 'isotope_data.json') with open(self.filename) as f: data_sec = False real = [] @@ -95,25 +94,11 @@ def _read_spe(self): imag = np.array(imag) hz = np.array(hz) - isotope = int(''.join(filter(str.isdigit, self.nucleus))) - element = ''.join(filter(str.isalpha, self.nucleus)).capitalize() - - b0_unit = ''.join(filter(str.isalpha, self.b0)).lower() - - with open(isotope_file) as f: - data = json.load(f) - gamma = data[element][str(isotope)]['Gamma'] - - if b0_unit == 't': - b0 = int(''.join(filter(str.isdigit, self.b0))) - ppm = hz / (b0 * gamma) - elif b0_unit == 'mhz': - b0 = int(''.join(filter(str.isdigit, self.b0))) - gamma_h = data['H']['1']['Gamma'] - ppm = hz / (b0/(gamma_h/gamma)) - else: - raise ValueError('B0 unit must be T or MHz.') - self.data = {'real': real, 'imag': imag, 'np': np_value, 'sw': sw, 'hz': hz, 'ppm': ppm} + try: + ppm = hz2ppm(hz, self.b0, self.nucleus) + self.data = {'real': real, 'imag': imag, 'np': np_value, 'sw': sw, 'hz': hz, 'ppm': ppm} + except ValueError as e: + print(f"Error converting to ppm: {e}") def _read_fid(self): """