rubycond_cb 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,85 @@
1
+ Metadata-Version: 2.3
2
+ Name: rubycond_cb
3
+ Version: 0.2.0
4
+ Summary: Tool for calibrating a spectrometer wavelengths
5
+ License: GPL-3.0-or-later
6
+ Author: Yiuri Garino
7
+ Author-email: yiuri.garino@cnrs.fr
8
+ Requires-Python: >=3.11
9
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Dist: configparser (>=6,<7)
15
+ Requires-Dist: lmfit (>=1.3,<2.0)
16
+ Requires-Dist: matplotlib (>=3.8.2,<4.0.0)
17
+ Requires-Dist: numpy (>=2.1,<3.0.0)
18
+ Requires-Dist: pillow (>=10.1.0)
19
+ Requires-Dist: pyqt5 (>=5.15.11,<6.0.0)
20
+ Requires-Dist: rubycond_of (>=0.1.0)
21
+ Project-URL: Repository, https://github.com/CelluleProjet/Rubycond_CB
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Rubycond_CB
25
+ Tool for calibrating the spectrometer wavelengths
26
+
27
+ <img width="1282" height="702" alt="1_open_file" src="https://github.com/user-attachments/assets/3d744deb-cf81-4d27-aae1-8c685986c98d" />
28
+
29
+ # Manual
30
+
31
+ 1) Select the Neon line on the left graph and the corresponding peak on the right graph.
32
+ The program automatically performs a peak fit within the pixel window defined in Delta (pixels), default 20 pixels.
33
+
34
+ 2) Add the pair of points using the **ADD** button. The points used for calibration are indicated on both the graphs and the table on the left.
35
+ <img width="1920" height="1032" alt="2_1_point" src="https://github.com/user-attachments/assets/7078a113-a26a-4ff4-9c1e-c06ab30deee6" />
36
+
37
+ 3) Repeat the operation, adding as many peaks as possible.
38
+ <img width="1920" height="1032" alt="3_n_point" src="https://github.com/user-attachments/assets/d46ac124-a0f3-407e-87d8-41a6133e65b5" />
39
+
40
+ 4) Use the **Simple Calib** button to perform the calibration.
41
+ The calibration result is displayed in the left graph, and the fit result is shown in the Fit Output window.
42
+ <img width="1920" height="1032" alt="4_output" src="https://github.com/user-attachments/assets/689a1baa-e4ec-4fb9-97c4-5956a9384e15" />
43
+
44
+ 5) Use the **Accept** button to send the calibration parameters to the main program
45
+ # Install
46
+ Use pip to install the program **within a virtual environment (strongly recommended).**
47
+ [Here's a short tutorial on installing a virtual environment.](https://github.com/CelluleProjet/Install/tree/main?tab=readme-ov-file#install-virtual-environment)
48
+ ```bash
49
+ pip install rubycond_CB
50
+ ```
51
+ # About
52
+ ## Author
53
+
54
+ **Yiuri Garino**
55
+
56
+ ## Contacts
57
+
58
+ **Yiuri Garino**
59
+ - yiuri.garino@cnrs.fr
60
+
61
+ **Silvia Boccato**
62
+ - silvia.boccato@cnrs.fr
63
+
64
+ <img src="https://github.com/CelluleProjet/Rubycond/assets/83216683/b728fe64-2752-4ecd-843b-09d335cf4f93" width="100" height="100">
65
+ <img src="https://github.com/CelluleProjet/Rubycond/assets/83216683/0a81ce1f-089f-49d8-ae65-d19af8078492" width="100" height="100">
66
+
67
+
68
+ [Cellule Projet](http://impmc.sorbonne-universite.fr/fr/plateformes-et-equipements/cellule-projet.html) @ [IMPMC](http://impmc.sorbonne-universite.fr/en/index.html)
69
+
70
+
71
+ ## License
72
+ **Rubycond_CB**: Tool for calibrating the spectrometer wavelengths
73
+
74
+
75
+ Copyright (c) 2022-2026 Yiuri Garino
76
+
77
+ **Rubycond_CB** is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
78
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
79
+
80
+ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
81
+
82
+ ## Release notes
83
+
84
+ Version 0.2.0 Release 260301: First release
85
+
@@ -0,0 +1,61 @@
1
+ # Rubycond_CB
2
+ Tool for calibrating the spectrometer wavelengths
3
+
4
+ <img width="1282" height="702" alt="1_open_file" src="https://github.com/user-attachments/assets/3d744deb-cf81-4d27-aae1-8c685986c98d" />
5
+
6
+ # Manual
7
+
8
+ 1) Select the Neon line on the left graph and the corresponding peak on the right graph.
9
+ The program automatically performs a peak fit within the pixel window defined in Delta (pixels), default 20 pixels.
10
+
11
+ 2) Add the pair of points using the **ADD** button. The points used for calibration are indicated on both the graphs and the table on the left.
12
+ <img width="1920" height="1032" alt="2_1_point" src="https://github.com/user-attachments/assets/7078a113-a26a-4ff4-9c1e-c06ab30deee6" />
13
+
14
+ 3) Repeat the operation, adding as many peaks as possible.
15
+ <img width="1920" height="1032" alt="3_n_point" src="https://github.com/user-attachments/assets/d46ac124-a0f3-407e-87d8-41a6133e65b5" />
16
+
17
+ 4) Use the **Simple Calib** button to perform the calibration.
18
+ The calibration result is displayed in the left graph, and the fit result is shown in the Fit Output window.
19
+ <img width="1920" height="1032" alt="4_output" src="https://github.com/user-attachments/assets/689a1baa-e4ec-4fb9-97c4-5956a9384e15" />
20
+
21
+ 5) Use the **Accept** button to send the calibration parameters to the main program
22
+ # Install
23
+ Use pip to install the program **within a virtual environment (strongly recommended).**
24
+ [Here's a short tutorial on installing a virtual environment.](https://github.com/CelluleProjet/Install/tree/main?tab=readme-ov-file#install-virtual-environment)
25
+ ```bash
26
+ pip install rubycond_CB
27
+ ```
28
+ # About
29
+ ## Author
30
+
31
+ **Yiuri Garino**
32
+
33
+ ## Contacts
34
+
35
+ **Yiuri Garino**
36
+ - yiuri.garino@cnrs.fr
37
+
38
+ **Silvia Boccato**
39
+ - silvia.boccato@cnrs.fr
40
+
41
+ <img src="https://github.com/CelluleProjet/Rubycond/assets/83216683/b728fe64-2752-4ecd-843b-09d335cf4f93" width="100" height="100">
42
+ <img src="https://github.com/CelluleProjet/Rubycond/assets/83216683/0a81ce1f-089f-49d8-ae65-d19af8078492" width="100" height="100">
43
+
44
+
45
+ [Cellule Projet](http://impmc.sorbonne-universite.fr/fr/plateformes-et-equipements/cellule-projet.html) @ [IMPMC](http://impmc.sorbonne-universite.fr/en/index.html)
46
+
47
+
48
+ ## License
49
+ **Rubycond_CB**: Tool for calibrating the spectrometer wavelengths
50
+
51
+
52
+ Copyright (c) 2022-2026 Yiuri Garino
53
+
54
+ **Rubycond_CB** is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
55
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
56
+
57
+ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
58
+
59
+ ## Release notes
60
+
61
+ Version 0.2.0 Release 260301: First release
@@ -0,0 +1,32 @@
1
+ [project]
2
+ name = "rubycond_cb"
3
+ version = "0.2.0"
4
+ description = "Tool for calibrating a spectrometer wavelengths "
5
+ authors = [
6
+ {name = "Yiuri Garino", email = "yiuri.garino@cnrs.fr"}
7
+ ]
8
+ license = "GPL-3.0-or-later"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ dependencies = [
12
+ "numpy (>=2.1,<3.0.0)",
13
+ "configparser (>=6,<7)",
14
+ "matplotlib (>=3.8.2,<4.0.0)",
15
+ "lmfit (>=1.3,<2.0)",
16
+ "pyqt5 (>=5.15.11,<6.0.0)",
17
+ "pillow (>=10.1.0)",
18
+ "rubycond_of (>=0.1.0)"
19
+ ]
20
+
21
+ [tool.poetry]
22
+ packages = [{ include = "rubycond_CB" }]
23
+
24
+ [project.urls]
25
+ repository = "https://github.com/CelluleProjet/Rubycond_CB"
26
+
27
+ [project.scripts]
28
+ rubycond_CB = "rubycond_CB.rubycond_CB:main"
29
+
30
+ [build-system]
31
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
32
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,277 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+
4
+ Title: Rubycond_CB: tool for calibrating the wavelength of the spectrometer
5
+
6
+ This file is part of Rubycond: Pressure by Ruby Luminescence (PRL) software to determine pressure in diamond anvil cell experiments.
7
+
8
+ Version 0.2.0
9
+ Release 260301
10
+
11
+ Author:
12
+
13
+ Yiuri Garino
14
+ yiuri.garino@cnrs.fr
15
+
16
+ Copyright (c) 2023-2026 Yiuri Garino
17
+
18
+ Download:
19
+ https://github.com/CelluleProjet/Rubycond_calc
20
+
21
+ License: GPLv3
22
+
23
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
24
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
25
+ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
26
+
27
+ """
28
+
29
+ def reset():
30
+ import sys
31
+
32
+ if hasattr(sys, 'ps1'):
33
+
34
+ #clean Console and Memory
35
+ from IPython import get_ipython
36
+ get_ipython().run_line_magic('clear','/')
37
+ get_ipython().run_line_magic('reset','-sf')
38
+ print("Running interactively")
39
+ print()
40
+ terminal = False
41
+ else:
42
+ print("Running in terminal")
43
+ print()
44
+ terminal = True
45
+
46
+ if __name__ == '__main__':
47
+ reset()
48
+
49
+ import configparser as cp
50
+ from pathlib import Path
51
+ import numpy as np
52
+ import matplotlib.pyplot as plt
53
+ import os
54
+ from datetime import datetime
55
+ from lmfit.models import LinearModel, GaussianModel, PolynomialModel
56
+ from PyQt5 import QtWidgets, QtCore, QtGui
57
+ from scipy.special import wofz
58
+ from scipy.interpolate import Akima1DInterpolator
59
+ from pathlib import Path
60
+
61
+ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
62
+
63
+ class my_model():
64
+ def __init__(self, debug = False):
65
+ self.debug = debug
66
+ self.version = 'RC_Model_11.py'
67
+ if self.debug: print('\nModel\n')
68
+ try:
69
+ #file_NEON = Path("Neon_Astrosurf.csv")
70
+ file_NEON = Path("Neon_PI.csv")
71
+ path_NEON = Path(__file__).parent.resolve() / file_NEON
72
+ except:
73
+ path_NEON = file_NEON
74
+
75
+
76
+ self.Neon_lines = np.loadtxt(path_NEON, delimiter=',')
77
+ self.peaks_data_x = np.zeros((2,2)) #Data from open file
78
+ self.peaks_data_y = np.zeros((2,2)) #Data from open file
79
+ self.peaks_data_x_simple_calib = np.zeros((2,2))
80
+
81
+ self.fit_delta_pixel = .6
82
+
83
+ self.Last_peaks_pixel_clicked = 0
84
+
85
+
86
+ self.delta = 20
87
+ self.calib_cn = [0,0,0,0] #max poly degree = 3
88
+
89
+ #
90
+ self.statusbar_message_ref = [print] #List of messages method (print, label, statusbar, etc)
91
+
92
+ def statusbar_message_add(self, method):
93
+ #print(method)
94
+ self.statusbar_message_ref.append(method)
95
+
96
+ def nearest_neon(self, value):
97
+ if value is not None:
98
+ i = abs(self.Neon_lines[:,0]-value).argmin()
99
+ data = self.Neon_lines[i]
100
+ #print(self.Neon_lines)
101
+ #print(abs(self.Neon_lines-value))
102
+ if self.debug :
103
+ print(f'input {i}: {value}')
104
+ print(f'output : {data}')
105
+ else:
106
+ data = 0
107
+ return data
108
+
109
+ def peaks_data_pixel(self, value):
110
+ if value is not None:
111
+ data = abs(self.peaks_data_x-value).argmin()
112
+
113
+
114
+ #print(abs(self.Neon_lines-value))
115
+ if self.debug :
116
+ print(self.peaks_data_x)
117
+ print(f'input : {value}')
118
+ print(f'output : {data}')
119
+ else:
120
+ data = 0
121
+ return data
122
+
123
+ def button_calc_simple_calib(self):
124
+ y1 = self.Neon_Left_reference
125
+ y2 = self.Neon_Right_reference
126
+ x1 = self.Peaks_Left_reference
127
+ x2 = self.Peaks_Right_reference
128
+ s = (y2 - y1)/(x2 - x1)
129
+ i = y1 - s*x1
130
+ size = len(self.peaks_data_x)
131
+ pixels = np.arange(0,size,1)
132
+ if self.debug :
133
+ print(f'slope : {s}')
134
+ print(f'intercept : {i}')
135
+ self.peaks_data_x_simple_calib = i + s*pixels
136
+
137
+ def format_fit_results(self, degree, res):
138
+ message = 'Fit Output\n'
139
+ message+= '\n'
140
+ # message+= 'Wavelengths (nm) = c0 + c1 * pixels + c2 * pixels\u00B2 + c3 * pixels\u00B3\n'
141
+ # message+= '\n\n'
142
+ for i in range(degree+1):
143
+
144
+ message+= f'c{i} = '
145
+ message+= f"{res.params[f'line_c{i}'].value:.5e}"
146
+ message+= '\n'
147
+ self.calib_cn[i] = res.params[f'line_c{i}'].value
148
+ for j in range(3 - degree):
149
+ message+= f'c{j + degree +1} = 0'
150
+ message+= '\n'
151
+ self.calib_cn[j + degree +1] = 0
152
+ print(message)
153
+ print(self.calib_cn)
154
+ self.print_message_output = message
155
+
156
+ def calib_poly_3(self, data_x, data_y):
157
+ degree = min(len(data_x)-1, 3)
158
+ model = PolynomialModel(degree=degree, prefix='line_')
159
+ pars = model.guess(data_y, data_x)
160
+ res = model.fit(data_y, pars, x = data_x)
161
+ if self.debug: pars.pretty_print()
162
+ #if self.debug: res.fit_report()#TODO restore in next version
163
+ print(res.fit_report()) #TODO cut in next version
164
+ size = len(self.peaks_data_x)
165
+ pixels = np.arange(0,size,1)
166
+
167
+ self.peaks_data_x_simple_calib = model.eval(res.params, x = pixels)
168
+
169
+ #prepare message to be used in layout_Output
170
+ self.format_fit_results(degree, res)
171
+
172
+ def fit_peak_range(self):
173
+ try:
174
+ center = self.Last_peaks_pixel_clicked
175
+ delta = self.delta
176
+ data_x_graph = self.peaks_data_x[center - delta: center + delta + 1]
177
+ data_x_pixel = np.linspace(center - delta, center + delta, delta*2+1)
178
+ data_y = self.peaks_data_y[center - delta: center + delta + 1]
179
+ data_x, data_y, init, fit_x, fit_y, res = self.fit_peak(data_x_pixel, data_y)
180
+
181
+ spl = Akima1DInterpolator(data_x_pixel, data_x_graph)
182
+
183
+ data_x = spl(data_x)
184
+ fit_x = spl(fit_x)
185
+ center_pixel = res.params['center'].value
186
+ center_graph = spl(center_pixel)
187
+ return data_x, data_y, init, fit_x, fit_y, center_graph, center_pixel
188
+ except:
189
+ return None
190
+
191
+ def fit_peak(self, data_x, data_y):
192
+ model = LinearModel() + GaussianModel()
193
+ pars = model.make_params()
194
+
195
+ y1 = data_y[0]
196
+ y2 = data_y[-1]
197
+ x1 = data_x[0]
198
+ x2 = data_x[-1]
199
+ slope = (y2 - y1)/(x2 - x1)
200
+ intercept = y1 - slope*x1
201
+ pars['slope'].value = slope
202
+ pars['intercept'].value = intercept
203
+ center = data_x[data_y.argmax()]
204
+ pars['center'].value = center
205
+ sigma = 5 * abs(data_x[1] - data_x[0])
206
+ pars['sigma'].value = sigma
207
+ height = data_y.max() - (intercept + slope * center)
208
+ pars['amplitude'].value = self.Gauss_amplitude(height, sigma)
209
+
210
+ init = model.eval(pars, x = data_x)
211
+ if self.debug: pars.pretty_print()
212
+ res = model.fit(data_y, pars, x = data_x)
213
+
214
+ if self.debug: print(res.fit_report())
215
+ size = len(self.peaks_data_x)
216
+ fit_x = np.linspace(data_x.min(),data_x.max(),500)
217
+ fit_y = model.eval(res.params, x = fit_x)
218
+
219
+ return data_x, data_y, init, fit_x, fit_y, res
220
+
221
+ def x_2_nm(self, x, i, c1, c2, c3):
222
+ return i +c1*x + c2*x**2 +c3*x**3
223
+
224
+ def Voigt(self, x, c0, c1, c2, c3, amplitude, center, sigma, gamma):
225
+ """
226
+ Return the Voigt line shape at x with Lorentzian component HWHM gamma
227
+ and Gaussian component sigma.
228
+ sigma = HWHM / sqrt(2 * log(2))
229
+
230
+ """
231
+ nm = c0 +c1*x + c2*x**2 +c3*x**3
232
+ return amplitude*np.real(wofz((nm - center + 1j*gamma)/sigma/np.sqrt(2))) / sigma /np.sqrt(2*np.pi)
233
+
234
+ def Voigt_amplitude(self, height, gamma, sigma):
235
+
236
+ return height*(sigma*np.sqrt(2*np.pi))/wofz((1j*gamma)/(sigma*np.sqrt(2))).real
237
+
238
+ def Gauss(self, x, c0, c1, c2, c3, amplitude, center, sigma):
239
+ #x pixel
240
+ nm = c0 +c1*x + c2*x**2 +c3*x**3
241
+ cm = 1e7/nm
242
+ center_cm = 1e7/center
243
+ return amplitude / sigma / np.sqrt(2*np.pi) * np.exp( - (cm -center_cm) **2 / 2 / sigma**2 )
244
+
245
+ def Gauss_amplitude(self, height, sigma):
246
+ return sigma * np.sqrt(2*np.pi) * height
247
+
248
+ #
249
+ def statusbar_message(self, message):
250
+ now = datetime.now()
251
+ text = now.strftime("%H:%M:%S : ") + message
252
+ for method in self.statusbar_message_ref:
253
+ method(text)
254
+
255
+ def error_box(self, error):
256
+ msgBox = QtWidgets.QMessageBox()
257
+ msgBox.setIcon(QtWidgets.QMessageBox.Critical)
258
+ msgBox.setWindowTitle("Script Error")
259
+ msgBox.setText(str(error))
260
+ msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
261
+ msgBox.exec()
262
+ '''
263
+ #%%
264
+ data_x = np.array((300,400,500,600))
265
+ data_y = np.array((300,400,500,600))
266
+ model = PolynomialModel(degree=2, prefix='line_')
267
+ pars = model.guess(data_y, data_x)
268
+ res = model.fit(data_y, pars, x = data_x)
269
+ pars.pretty_print()
270
+ res.params.pretty_print()
271
+ res.fit_report()
272
+
273
+ Fit = self.model.eval(self.out.params, x = x_fit_lmfit)
274
+ self.center_pk = self.out.params['pk_center'].value
275
+ self.out = self.model.fit(y_fit, self.pars, x = x, max_nfev = self.Fit_iter_lim.get())
276
+ comps = self.out.eval_components(x = x_fit_lmfit)
277
+ '''
@@ -0,0 +1,25 @@
1
+ 585.0936329588015, 0.9920106524633822
2
+ 588.1179775280899, 0.1238348868175766
3
+ 594.3258426966293, 0.23435419440745675
4
+ 597.3501872659176, 0.0679094540612517
5
+ 602.9213483146068, 0.06924101198402122
6
+ 607.059925093633, 0.18375499334221035
7
+ 609.2883895131087, 0.2583222370173103
8
+ 614.0636704119851, 0.4194407456724367
9
+ 616.1329588014981, 0.14647137150466039
10
+ 621.3857677902622, 0.118508655126498
11
+ 626.3202247191011, 0.2250332889480693
12
+ 630.1404494382023, 0.07589880159786955
13
+ 632.8464419475656, 0.18242343541944084
14
+ 637.7808988764045, 0.2663115845539281
15
+ 639.8501872659176, 0.29693741677762975
16
+ 650.3558052434457, 0.16644474034620504
17
+ 652.9026217228464, 0.07589880159786955
18
+ 659.5880149812734, 0.0732356857523303
19
+ 667.5468164794008, 0.11584553928095864
20
+ 671.5262172284645, 0.1131824234354194
21
+ 692.6966292134832, 0.09986684420772307
22
+ 703.0430711610487, 0.2809587217043942
23
+ 717.368913857678, 0.011984021304926706
24
+ 724.5318352059926, 0.08655126498002663
25
+ 744.1104868913858, 0.01464713715046595
@@ -0,0 +1,20 @@
1
+ 607.43377, 0.18375499334221035
2
+ 609.61631, 0.2583222370173103
3
+ 614.30626, 0.4194407456724367
4
+ 616.35939, 0.14647137150466039
5
+ 621.72812, 0.118508655126498
6
+ 626.6495, 0.2250332889480693
7
+ 630.4789, 0.07589880159786955
8
+ 633.44278, 0.18242343541944084
9
+ 638.29917, 0.2663115845539281
10
+ 640.2246, 0.29693741677762975
11
+ 650.65281, 0.16644474034620504
12
+ 653.28822, 0.07589880159786955
13
+ 659.89529, 0.0732356857523303
14
+ 667.82764, 0.11584553928095864
15
+ 671.7043, 0.1131824234354194
16
+ 692.94673, 0.09986684420772307
17
+ 703.24131, 0.2809587217043942
18
+ 717.39381, 0.011984021304926706
19
+ 724.51666, 0.08655126498002663
20
+ 743.8899, 0.01464713715046595