diff --git a/pyproject.toml b/pyproject.toml
index 5841189..30ac101 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -61,8 +61,6 @@ testpaths = "tests"
addopts = "--cov -v"
filterwarnings = 'ignore:datetime.datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning' # 3rd party
-
-
[tool.box]
builder = "rye"
app_entry = "rimsschemedrawer.app:run_gui"
diff --git a/src/rimsschemedrawer/gui.py b/src/rimsschemedrawer/gui.py
index de951ec..8357486 100644
--- a/src/rimsschemedrawer/gui.py
+++ b/src/rimsschemedrawer/gui.py
@@ -72,6 +72,7 @@ def __init__(self):
self.cmb_lasers = None
self.chk_lowlying = []
self.chk_forbidden = []
+ self.chk_laststep = None
# settings line edits
self.edt_sett_plttitle = QtWidgets.QLineEdit()
@@ -251,6 +252,16 @@ def init_ui(self):
"Check this box to mark the\n" "transition as forbidden."
)
+ # draw last step to IP
+ self.chk_laststep = QtWidgets.QCheckBox("Draw last step to IP?")
+ self.chk_laststep.setToolTip(
+ "Check this box to draw the last step, if it is below the IP, to the IP.\n"
+ "The wavelength will then be labeled as an upper limit `<` and no level\n"
+ "information will be printed. This option has no influence if the last\n"
+ "step specified above is already above the IP!"
+ )
+ layout.addWidget(self.chk_laststep, 4 + len(self.lbl_steps), 0, 1, 2)
+
# name the labels
self.set_label_names()
@@ -267,10 +278,10 @@ def init_ui(self):
# Set the elements
element_lbl = QtWidgets.QLabel("Element")
- layout.addWidget(element_lbl, 4 + len(self.lbl_steps), 0, 1, 1)
+ layout.addWidget(element_lbl, 5 + len(self.lbl_steps), 0, 1, 1)
cmb_element = QtWidgets.QComboBox()
cmb_element.addItems(ut.get_elements())
- layout.addWidget(cmb_element, 4 + len(self.lbl_steps), 1, 1, 1)
+ layout.addWidget(cmb_element, 5 + len(self.lbl_steps), 1, 1, 1)
cmb_element.setToolTip("Select the element to set the IP.")
cmb_element.currentIndexChanged.connect(lambda x: self.set_ip(x))
cmb_element.setCurrentIndex(0)
@@ -279,7 +290,7 @@ def init_ui(self):
# Laser selection
laser_lbls = QtWidgets.QLabel("Lasers")
- layout.addWidget(laser_lbls, 5 + len(self.lbl_steps), 0, 1, 1)
+ layout.addWidget(laser_lbls, 6 + len(self.lbl_steps), 0, 1, 1)
cmb_lasers = QtWidgets.QComboBox()
cmb_lasers.addItems(ut.LASERS)
cmb_lasers.setToolTip(
@@ -289,7 +300,7 @@ def init_ui(self):
"to the RIMS database website "
"and its entry will be saved to the configuration file."
)
- layout.addWidget(cmb_lasers, 5 + len(self.lbl_steps), 1, 1, 1)
+ layout.addWidget(cmb_lasers, 6 + len(self.lbl_steps), 1, 1, 1)
self.cmb_lasers = cmb_lasers
# set sizes and validators of boxes defined outside loop
@@ -740,22 +751,37 @@ def load_config(self, **kwargs):
self.edt_gslevel.setText(str(config_parser.gs_level))
self.edt_gsterm.setText(config_parser.gs_term_no_formatting)
+
+ # get the data to fill from
+ if config_parser.sett_unit_nm:
+ value_list = config_parser.step_nm
+ else:
+ value_list = config_parser.step_levels
+ step_terms_no_formatting = config_parser.step_terms_no_formatting
+ transition_strengths = config_parser.transition_strengths
+ is_low_lying = config_parser.is_low_lying
+ step_forbidden = config_parser.step_forbidden
+
+ # cut last index off if we are dealing with last_step_to_ip defined
+ if config_parser.last_step_to_ip_mode:
+ value_list = value_list[:-1]
+ step_terms_no_formatting = step_terms_no_formatting[:-1]
+ transition_strengths = transition_strengths[:-1]
+ is_low_lying = is_low_lying[:-1]
+ step_forbidden = step_forbidden[:-1]
+
for it in range(
len(self.edt_level)
): # only loop through as many entries as there are
try:
- if config_parser.sett_unit_nm:
- value_list = config_parser.step_nm
- else:
- value_list = config_parser.step_levels
self.edt_level[it].setText(str(value_list[it]))
- self.edt_term[it].setText(config_parser.step_terms_no_formatting[it])
+ self.edt_term[it].setText(step_terms_no_formatting[it])
- trans_strength = config_parser.transition_strengths[it]
+ trans_strength = transition_strengths[it]
if trans_strength > 0:
self.edt_transition_strengths[it].setText(str(trans_strength))
- self.chk_lowlying[it].setChecked(config_parser.is_low_lying[it])
- self.chk_forbidden[it].setChecked(config_parser.step_forbidden[it])
+ self.chk_lowlying[it].setChecked(is_low_lying[it])
+ self.chk_forbidden[it].setChecked(step_forbidden[it])
except IndexError:
self.edt_level[it].setText("")
self.edt_term[it].setText("")
@@ -763,6 +789,9 @@ def load_config(self, **kwargs):
self.chk_lowlying[it].setChecked(False)
self.chk_forbidden[it].setChecked(False)
+ # Last step to IP
+ self.chk_laststep.setChecked(config_parser.last_step_to_ip)
+
# IP level
self.cmb_element.setCurrentText(config_parser.element)
if config_parser.element_guessed:
@@ -850,6 +879,7 @@ def write_json(self) -> dict:
savedict["scheme"]["ip_term"] = self.edt_ipterm.text()
savedict["scheme"]["element"] = self.cmb_element.currentText()
savedict["scheme"]["lasers"] = self.cmb_lasers.currentText()
+ savedict["scheme"]["last_step_to_ip"] = self.chk_laststep.isChecked()
# save the settings
savedict["settings"]["fig_width"] = self.edt_sett_figwidth.text()
diff --git a/src/rimsschemedrawer/json_parser.py b/src/rimsschemedrawer/json_parser.py
index 436e374..ebd6ab1 100644
--- a/src/rimsschemedrawer/json_parser.py
+++ b/src/rimsschemedrawer/json_parser.py
@@ -21,6 +21,8 @@ def __init__(self, data: Dict):
self.data = data
self._element_guessed = False
+ self._last_step_to_ip_mode = False
+
self._parse_data_scheme()
self._parse_data_settings()
@@ -81,6 +83,16 @@ def lasers(self) -> str:
"""Get the types of lasers used in this scheme (defaults to Ti:Sa)."""
return self._lasers
+ @property
+ def last_step_to_ip(self) -> bool:
+ """Get the last step to the ionization potential setup in file."""
+ return self._last_step_to_ip
+
+ @property
+ def last_step_to_ip_mode(self) -> bool:
+ """Get if we are actually in last step to IP mode?"""
+ return self._last_step_to_ip_mode
+
@property
def number_of_levels(self) -> int:
"""Get the number of steps in the scheme."""
@@ -223,6 +235,8 @@ def scheme_table(self, prec: int = 3, prec_strength: int = 1) -> Tuple[List, Lis
Table: All entries are formatted as strings!
+ fixme: Modifications if in last step to IP mode
+
:param prec: Precision for the wavelength and steps.
:param prec_strength: Precision for the transition strength.
@@ -365,6 +379,12 @@ def _parse_data_scheme(self):
except KeyError:
self._lasers = ut.LASERS[0]
+ # get last step to IP
+ last_step_to_ip_default = ut.DEFAULT_SETTINGS["scheme"]["last_step_to_ip"]
+ self._last_step_to_ip = self.data["scheme"].get(
+ "last_step_to_ip", last_step_to_ip_default
+ )
+
# Get the step levels and save them as cm-1 (transform if in nm)
step_levels = []
idx = 0
@@ -430,6 +450,19 @@ def _parse_data_scheme(self):
self._step_levels_cm[it] - self._step_levels_cm[it - 1]
)
+ # adjust scheme if last_step_to_ip and set mode if required
+ if self._last_step_to_ip and self._step_levels_cm[-1] < self._ip_level:
+ self._last_step_to_ip_mode = True
+ # append the last step
+ self._step_levels_cm = np.append(self._step_levels_cm, self._ip_level)
+ self._steps_nm = np.append(
+ self._steps_nm, ut.cm_2_to_nm(self._ip_level - self._step_levels_cm[-2])
+ )
+ self._forbidden = np.append(self._forbidden, False)
+ self._low_lying = np.append(self._low_lying, False)
+ self._transition_strength = np.append(self._transition_strength, 0)
+ self._step_term = np.append(self._step_term, "")
+
def _parse_data_key(self, key: str, dtype: type, default: any) -> np.ndarray:
"""Parse a key from the data and return values with the correct type.
diff --git a/src/rimsschemedrawer/plotter.py b/src/rimsschemedrawer/plotter.py
index 840efcc..4e19897 100644
--- a/src/rimsschemedrawer/plotter.py
+++ b/src/rimsschemedrawer/plotter.py
@@ -227,6 +227,13 @@ def _plotit(self):
xvalplot = firstarrowxmfl
else:
xvalplot = xval
+ # face color for arrow
+ fc_col = col
+ if (
+ self.config_parser.last_step_to_ip_mode
+ and it == len(lambda_steps) - 1
+ ):
+ fc_col = "None"
# now plot the arrow
self._axes.arrow(
xvalplot,
@@ -234,7 +241,7 @@ def _plotit(self):
0,
wstp,
width=sett_arr,
- fc=col,
+ fc=fc_col,
ec=col,
length_includes_head=True,
head_width=sett_arr_head,
@@ -254,14 +261,15 @@ def _plotit(self):
)
# draw a little solid line for the last/end state
- if it == len(lambda_steps) - 1:
- self._axes.hlines(
- tstp,
- xmin=xval - 0.5,
- xmax=xval + 0.5,
- linestyle="solid",
- color=self.colmain,
- )
+ if not self.config_parser.last_step_to_ip_mode:
+ if it == len(lambda_steps) - 1:
+ self._axes.hlines(
+ tstp,
+ xmin=xval - 0.5,
+ xmax=xval + 0.5,
+ linestyle="solid",
+ color=self.colmain,
+ )
# alignment of labels
if xval <= 5.0:
@@ -276,6 +284,11 @@ def _plotit(self):
if not forbidden_steps[it] or show_forbidden_trans == "x-out":
# wavelength text and transition strength
lambdastr = f"{lambda_steps[it]:.{prec_lambda}f}$\\,$nm"
+ if (
+ self.config_parser.last_step_to_ip_mode
+ and it == len(lambda_steps) - 1
+ ):
+ lambdastr = f"<{lambdastr}"
if (
show_trans_strength
and (tmp_strength := transition_strengths_steps[it]) != 0
@@ -309,6 +322,7 @@ def _plotit(self):
)
# level text
+ # fixme: only do this if we are not in the last step to IP mode
levelstr = f"{tstp:.{prec_level}f}$\\,$cm$^{{-1}}$"
if term_symb[it] is not None:
levelstr += f"{lbreak}{term_symb[it]}"
@@ -318,15 +332,20 @@ def _plotit(self):
else:
leveltextypos = tstp - 0.01 * totwavenumber_photons
leveltextvaalign = "top"
- self._axes.text(
- xloc_levelstr,
- leveltextypos,
- levelstr,
- color=self.colmain,
- ha=halignlev,
- va=leveltextvaalign,
- size=fsz_labels,
- )
+
+ if (
+ not self.config_parser.last_step_to_ip_mode
+ or it != len(lambda_steps) - 1
+ ):
+ self._axes.text(
+ xloc_levelstr,
+ leveltextypos,
+ levelstr,
+ color=self.colmain,
+ ha=halignlev,
+ va=leveltextvaalign,
+ size=fsz_labels,
+ )
# update yval_bott
yval_bott = transition_steps[it]
@@ -348,7 +367,7 @@ def _plotit(self):
color=self.colmain,
)
- for it in range(len(wavenumber_es)):
+ for it in range(len(wavenumber_es)): # these are never steps to IP
col = ut.color_wavelength(lambda_step_es[it], self.darkmode)
# values for spacing and distance
xval = firstarrowxmfl + x_spacing_es + it * x_spacing_es
diff --git a/src/rimsschemedrawer/utils.py b/src/rimsschemedrawer/utils.py
index 144ff40..7037fae 100644
--- a/src/rimsschemedrawer/utils.py
+++ b/src/rimsschemedrawer/utils.py
@@ -30,6 +30,7 @@
"scheme": {
"gs_term": "",
"ip_term": "",
+ "last_step_to_ip": False,
},
}
diff --git a/tests/data/draw_last_false.json b/tests/data/draw_last_false.json
new file mode 100644
index 0000000..ccdce3c
--- /dev/null
+++ b/tests/data/draw_last_false.json
@@ -0,0 +1,67 @@
+{
+ "scheme": {
+ "element": "Fe",
+ "gs_level": "0.0",
+ "gs_term": "5D4",
+ "ip_term": "",
+ "lasers": "Ti:Sa",
+ "last_step_to_ip": true,
+ "step_forbidden0": false,
+ "step_forbidden1": false,
+ "step_forbidden2": false,
+ "step_forbidden3": false,
+ "step_forbidden4": false,
+ "step_forbidden5": false,
+ "step_forbidden6": false,
+ "step_level0": "26140.196",
+ "step_level1": "50530.829",
+ "step_level2": "64126.024",
+ "step_level3": "",
+ "step_level4": "",
+ "step_level5": "",
+ "step_level6": "",
+ "step_lowlying0": false,
+ "step_lowlying1": false,
+ "step_lowlying2": false,
+ "step_lowlying3": false,
+ "step_lowlying4": false,
+ "step_lowlying5": false,
+ "step_lowlying6": false,
+ "step_term0": "5D3",
+ "step_term1": "5D3",
+ "step_term2": "",
+ "step_term3": "",
+ "step_term4": "",
+ "step_term5": "",
+ "step_term6": "",
+ "trans_strength0": "",
+ "trans_strength1": "",
+ "trans_strength2": "",
+ "trans_strength3": "",
+ "trans_strength4": "",
+ "trans_strength5": "",
+ "trans_strength6": "",
+ "unit": "cm-1"
+ },
+ "settings": {
+ "arrow_head_width": "0.6",
+ "arrow_width": "0.2",
+ "fig_height": "8.0",
+ "fig_width": "5.0",
+ "fs_axes": "11.0",
+ "fs_axes_labels": "11.0",
+ "fs_labels": "11.0",
+ "fs_title": "14.0",
+ "headspace": "2500.0",
+ "ip_label_pos": "Bottom",
+ "line_breaks": true,
+ "plot_style": "light",
+ "plot_title": "",
+ "prec_level": "0",
+ "prec_wavelength": "3",
+ "show_cm-1_axis": true,
+ "show_eV_axis": true,
+ "show_forbidden_transitions": "x-out",
+ "show_transition_strength": true
+ }
+}
diff --git a/tests/data/draw_last_true.json b/tests/data/draw_last_true.json
new file mode 100644
index 0000000..50fb10d
--- /dev/null
+++ b/tests/data/draw_last_true.json
@@ -0,0 +1,67 @@
+{
+ "scheme": {
+ "element": "Fe",
+ "gs_level": "0.0",
+ "gs_term": "5D4",
+ "ip_term": "",
+ "lasers": "Ti:Sa",
+ "last_step_to_ip": true,
+ "step_forbidden0": false,
+ "step_forbidden1": false,
+ "step_forbidden2": false,
+ "step_forbidden3": false,
+ "step_forbidden4": false,
+ "step_forbidden5": false,
+ "step_forbidden6": false,
+ "step_level0": "26140.196",
+ "step_level1": "50530.829",
+ "step_level2": "",
+ "step_level3": "",
+ "step_level4": "",
+ "step_level5": "",
+ "step_level6": "",
+ "step_lowlying0": false,
+ "step_lowlying1": false,
+ "step_lowlying2": false,
+ "step_lowlying3": false,
+ "step_lowlying4": false,
+ "step_lowlying5": false,
+ "step_lowlying6": false,
+ "step_term0": "5D3",
+ "step_term1": "5D3",
+ "step_term2": "",
+ "step_term3": "",
+ "step_term4": "",
+ "step_term5": "",
+ "step_term6": "",
+ "trans_strength0": "",
+ "trans_strength1": "",
+ "trans_strength2": "",
+ "trans_strength3": "",
+ "trans_strength4": "",
+ "trans_strength5": "",
+ "trans_strength6": "",
+ "unit": "cm-1"
+ },
+ "settings": {
+ "arrow_head_width": "0.6",
+ "arrow_width": "0.2",
+ "fig_height": "8.0",
+ "fig_width": "5.0",
+ "fs_axes": "11.0",
+ "fs_axes_labels": "11.0",
+ "fs_labels": "11.0",
+ "fs_title": "14.0",
+ "headspace": "2500.0",
+ "ip_label_pos": "Bottom",
+ "line_breaks": true,
+ "plot_style": "light",
+ "plot_title": "",
+ "prec_level": "0",
+ "prec_wavelength": "3",
+ "show_cm-1_axis": true,
+ "show_eV_axis": true,
+ "show_forbidden_transitions": "x-out",
+ "show_transition_strength": true
+ }
+}
diff --git a/tests/test_json_parser.py b/tests/test_json_parser.py
index e961191..4af4e92 100644
--- a/tests/test_json_parser.py
+++ b/tests/test_json_parser.py
@@ -18,6 +18,8 @@ def test_config_parser(data_path, fname):
parser = jp.ConfigParser(data)
assert parser.lasers == "Ti:Sa"
+ assert not parser.last_step_to_ip_mode
+ assert not parser.last_step_to_ip
@pytest.mark.parametrize(
@@ -118,3 +120,18 @@ def test_json_reader_new(data_path, tmp_path):
assert isinstance(data_in, dict)
assert "scheme" in data_in.keys()
assert "settings" in data_in.keys()
+
+
+@pytest.mark.parametrize("selector", [True, False])
+def test_json_reader_last_step_to_ip(data_path, selector):
+ """Check if last step to IP is correctly parsed."""
+ if selector:
+ fin = data_path.joinpath("draw_last_true.json")
+ else:
+ fin = data_path.joinpath("draw_last_false.json")
+ data = jp.json_reader(fin)
+
+ parser = jp.ConfigParser(data)
+
+ assert parser.last_step_to_ip
+ assert parser.last_step_to_ip_mode is selector