Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cpp/RAT
2 changes: 1 addition & 1 deletion ratapi/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def make_problem(project: ratapi.Project) -> ProblemDefinition:
problem.numberOfContrasts = len(project.contrasts)
problem.geometry = project.geometry
problem.useImaginary = project.absorption
problem.repeatLayers = [1] * len(project.contrasts)
problem.repeatLayers = [contrast.repeat_layers for contrast in project.contrasts]
problem.contrastBackgroundParams = contrast_background_params
problem.contrastBackgroundTypes = contrast_background_types
problem.contrastBackgroundActions = [contrast.background_action for contrast in project.contrasts]
Expand Down
9 changes: 9 additions & 0 deletions ratapi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ class Contrast(RATModel):
The name of the instrument resolution for this contrast.
resample : bool
Whether adaptive resampling should be used for interface microslicing.
repeat_layers : int
For standard layers, the number of times the set of layers defined in the model should be repeated.
model : list[str]
If this is a standard layers model, this should be a list of layer names
that make up the slab model for this contrast.
Expand All @@ -180,6 +182,7 @@ class Contrast(RATModel):
scalefactor: str = ""
resolution: str = ""
resample: bool = False
repeat_layers: int = Field(default=1, gt=0)
model: list[str] = []

@model_validator(mode="before")
Expand Down Expand Up @@ -208,6 +211,7 @@ def __str__(self):
self.scalefactor,
self.resolution,
self.resample,
self.repeat_layers,
model_entry,
]
)
Expand Down Expand Up @@ -238,6 +242,8 @@ class ContrastWithRatio(RATModel):
The name of the instrument resolution for this contrast.
resample : bool
Whether adaptive resampling should be used for interface microslicing.
repeat_layers : int
For standard layers, the number of times the set of layers defined in the model should be repeated.
domain_ratio : str
The name of the domain ratio parameter describing how the first domain should be weighted
relative to the second.
Expand All @@ -258,6 +264,7 @@ class ContrastWithRatio(RATModel):
scalefactor: str = ""
resolution: str = ""
resample: bool = False
repeat_layers: int = Field(default=1, gt=0)
domain_ratio: str = ""
model: list[str] = []

Expand All @@ -276,6 +283,8 @@ def __str__(self):
self.scalefactor,
self.resolution,
self.resample,
self.repeat_layers,
self.domain_ratio,
model_entry,
]
)
Expand Down
31 changes: 29 additions & 2 deletions ratapi/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ def model_post_init(self, __context: Any) -> None:
"""Set up the Class to protect against disallowed modification.

We initialise the class handle in the ClassLists for empty data fields, set protected parameters, get names of
all defined parameters, determine the contents of the "model" field in contrasts,
and wrap ClassList routines to control revalidation.
all defined parameters, determine the contents of the "model" field in contrasts, and wrap ClassList routines
to control revalidation.
"""
# Ensure all ClassLists have the correct _class_handle defined
for field in (fields := Project.model_fields):
Expand Down Expand Up @@ -454,6 +454,33 @@ def set_layers(self) -> "Project":
self.layers.data = []
return self

@model_validator(mode="after")
def set_repeat_layers(self) -> "Project":
"""If we are not using a standard layers model, warn that the repeat layers setting is not valid."""
if self.model != LayerModels.StandardLayers:
for contrast in self.contrasts:
if "repeat_layers" in contrast.model_fields_set and contrast.repeat_layers != 1:
warnings.warn(
'For a custom layers or custom XY calculation, the "repeat_layers" setting for each '
"contrast is not valid - resetting to 1.",
stacklevel=2,
)
contrast.repeat_layers = 1
return self

@model_validator(mode="after")
def set_resample(self) -> "Project":
"""If we are using a custom XY model, warn that the resample setting for each contrast must always be True."""
if self.model == LayerModels.CustomXY:
for contrast in self.contrasts:
if "resample" in contrast.model_fields_set and contrast.resample is False:
warnings.warn(
'For a custom XY calculation, "resample" must be True for each contrast - resetting to True.',
stacklevel=2,
)
contrast.resample = True
return self

@model_validator(mode="after")
def set_calculation(self) -> "Project":
"""Apply the calc setting to the project."""
Expand Down
2 changes: 1 addition & 1 deletion tests/test_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ def custom_xy_problem(test_names, test_checks):
problem.contrastResolutionTypes = ["constant"]
problem.contrastCustomFiles = [1]
problem.contrastDomainRatios = [0]
problem.resample = [False]
problem.resample = [True]
problem.dataPresent = [0]
problem.data = [np.empty([0, 6])]
problem.dataLimits = [[0.0, 0.0]]
Expand Down
40 changes: 40 additions & 0 deletions tests/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,46 @@ def test_set_layers(project_parameters: dict) -> None:
assert project.layers == []


@pytest.mark.parametrize(
"project_parameters",
[
(
{
"model": LayerModels.CustomLayers,
"contrasts": [ratapi.models.Contrast(name="Test Contrast", repeat_layers=2)],
}
),
({"model": LayerModels.CustomXY, "contrasts": [ratapi.models.Contrast(name="Test Contrast", repeat_layers=2)]}),
],
)
def test_set_repeat_layers(project_parameters: dict) -> None:
"""If we are using a custom layers of custom XY model, the "resample" field of all the contrasts should always
be 1."""
with pytest.warns(
match='For a custom layers or custom XY calculation, the "repeat_layers" setting for each '
"contrast is not valid - resetting to 1."
):
project = ratapi.Project(**project_parameters)
assert all(contrast.repeat_layers == 1 for contrast in project.contrasts)


@pytest.mark.parametrize(
"project_parameters",
[
({"model": LayerModels.CustomXY, "contrasts": [ratapi.models.Contrast(name="Test Contrast")]}),
],
)
def test_set_resample(project_parameters: dict) -> None:
"""If we are using a custom XY model, the "resample" field of all the contrasts should always be True."""
project = ratapi.Project(**project_parameters)
assert all(contrast.resample for contrast in project.contrasts)
with pytest.warns(
match='For a custom XY calculation, "resample" must be True for each contrast - resetting to True.'
):
project.contrasts.append(name="New Contrast", resample=False)
assert all(contrast.resample for contrast in project.contrasts)


@pytest.mark.parametrize(
["input_calculation", "input_contrast", "new_calculation", "new_contrast_model", "num_domain_ratios"],
[
Expand Down
Loading