Skip to content

Commit d7dd9d9

Browse files
committed
added constraint adjustment
1 parent 92c6d67 commit d7dd9d9

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

RATapi/utils/convert.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Utilities for converting input files to Python `Project`s."""
22

33
import json
4+
import warnings
45
from collections.abc import Iterable
56
from os import PathLike
67
from pathlib import Path
@@ -67,7 +68,7 @@ def zip_if_several(*params) -> Union[tuple, list[tuple]]:
6768
return [params]
6869

6970
def read_param(names, constrs, values, fits):
70-
"""Read in a parameter list from the relevant keys.
71+
"""Read in a parameter list from the relevant keys, and fix constraints for non-fit parameters.
7172
7273
Parameters
7374
----------
@@ -77,10 +78,53 @@ def read_param(names, constrs, values, fits):
7778
7879
Returns
7980
-------
80-
list
81+
ClassList
8182
A list of all relevant parameters.
8283
"""
8384

85+
def fix_invalid_constraints(name: str, constrs: tuple[float, float], value: float) -> tuple[float, float]:
86+
"""Check that constraints are valid and fix them if they aren't.
87+
88+
RasCAL-1 allowed the constraints of non-fit parameters to be invalid, which means
89+
we need to fix them here so that the project is valid.
90+
91+
Parameters
92+
----------
93+
name: str
94+
The name of the parameter.
95+
constrs : tuple[float, float]
96+
The constraints of the parameter (min and max, respectively)
97+
value : float
98+
The value of the parameter.
99+
100+
Returns
101+
-------
102+
tuple[float, float]
103+
The adjusted constraints (identical to constrs if constraints were valid)
104+
105+
"""
106+
new_constrs = (min(constrs[0], value), max(constrs[1], value))
107+
if new_constrs[0] != constrs[0] or new_constrs[1] != constrs[1]:
108+
warnings.warn(f"The parameter {name} has invalid constraints,"
109+
" these have been adjusted to satisfy the current value of the parameter.",
110+
stacklevel=2)
111+
return new_constrs
112+
113+
# adjust invalid constraints
114+
# if just one item in the classlist, these objects won't be in lists
115+
if not isinstance(fit := mat_project[fits], Iterable):
116+
if not fit:
117+
mat_project[constrs] = fix_invalid_constraints(mat_project[names],
118+
mat_project[constrs],
119+
mat_project[values])
120+
# else they will be iterable
121+
else:
122+
for i, fit in enumerate(mat_project[fits]):
123+
if not fit:
124+
mat_project[constrs][i] = fix_invalid_constraints(mat_project[names][i],
125+
mat_project[constrs][i],
126+
mat_project[values][i])
127+
84128
return ClassList(
85129
[
86130
Parameter(

tests/test_convert.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ def mock_load(ignored_filename, **ignored_settings):
9999
assert getattr(converted_project, class_list) == getattr(original_project, class_list)
100100

101101

102+
def test_invalid_constraints():
103+
"""Test that invalid constraints are fixed where necessary."""
104+
with pytest.warns(match="The parameter Background parameter 1 has invalid constraints,"
105+
" these have been adjusted to satisfy the current value of the parameter."):
106+
output_project = r1_to_project_class(pathlib.Path(TEST_DIR_PATH, "R1DoubleBilayerVolumeModel.mat"))
107+
108+
assert output_project.background_parameters[0].min == output_project.background_parameters[0].value
109+
110+
111+
102112
@pytest.mark.parametrize(
103113
"project",
104114
[
10.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)