From 4376c3805d3cc35e647bafea9ddda4334819b641 Mon Sep 17 00:00:00 2001 From: alexhroom Date: Tue, 18 Feb 2025 09:56:35 +0000 Subject: [PATCH 1/5] ran ruff pydocstyle ruleset --- RATapi/controls.py | 3 ++- RATapi/examples/bayes_benchmark/bayes_benchmark.py | 6 ++++-- RATapi/inputs.py | 1 + RATapi/models.py | 2 -- RATapi/outputs.py | 6 ++++-- RATapi/run.py | 4 ++++ RATapi/utils/convert.py | 6 +++++- RATapi/utils/plotting.py | 4 +++- pyproject.toml | 14 ++++++++++++-- tests/conftest.py | 1 - tests/test_classlist.py | 3 ++- tests/test_models.py | 1 - 12 files changed, 37 insertions(+), 14 deletions(-) diff --git a/RATapi/controls.py b/RATapi/controls.py index e874e6f3..6f7fda44 100644 --- a/RATapi/controls.py +++ b/RATapi/controls.py @@ -205,10 +205,11 @@ def initialise_IPC(self): def sendStopEvent(self): """Sends the stop event via the inter-process communication file. - Warnings + Warnings: -------- UserWarning Raised if we try to delete an IPC file that was not initialised. + """ if os.path.isfile(self._IPCFilePath): with open(self._IPCFilePath, "wb") as f: diff --git a/RATapi/examples/bayes_benchmark/bayes_benchmark.py b/RATapi/examples/bayes_benchmark/bayes_benchmark.py index 2cec2e3e..1d2971b0 100644 --- a/RATapi/examples/bayes_benchmark/bayes_benchmark.py +++ b/RATapi/examples/bayes_benchmark/bayes_benchmark.py @@ -1,5 +1,4 @@ -""" -This example compares three Bayesian posteriors for a low-dimensional +"""This example compares three Bayesian posteriors for a low-dimensional example: a posterior generated by DREAM, one generated by NS, and one calculated directly. @@ -191,6 +190,7 @@ def calculate_posterior(roughness_index: int, background_index: int) -> float: ------- float The value of exp(-chi^2 / 2) for the given roughness and background values. + """ problem.parameters[0].value = roughness[roughness_index] problem.background_parameters[0].value = background[background_index] @@ -265,6 +265,7 @@ def calculate_posterior(roughness_index: int, background_index: int, scalefactor ------- float The value of exp(-chi^2 / 2) for the given roughness and background values. + """ problem.parameters[0].value = roughness[roughness_index] problem.background_parameters[0].value = background[background_index] @@ -300,6 +301,7 @@ def plot_posterior_comparison( The BayesResults object from a DREAM calculation. calc_results : CalculationResults The results from a direct calculation. + """ num_params = calc_results.distribution.ndim fig, axes = plt.subplots(3, num_params, figsize=(3 * num_params, 9)) diff --git a/RATapi/inputs.py b/RATapi/inputs.py index 812b9ac4..d61a1901 100644 --- a/RATapi/inputs.py +++ b/RATapi/inputs.py @@ -56,6 +56,7 @@ class FileHandles: ---------- files : ClassList[CustomFile] A list of custom file models. + """ def __init__(self, files=None): diff --git a/RATapi/models.py b/RATapi/models.py index 3d9f7097..09fd8a3d 100644 --- a/RATapi/models.py +++ b/RATapi/models.py @@ -179,7 +179,6 @@ class Contrast(RATModel): @classmethod def domain_ratio_error(cls, data: Any): """If the extra input 'domain_ratio' is given, give a more descriptive error.""" - if isinstance(data, dict) and data.get("domain_ratio", False): raise ValueError( "The Contrast class does not support domain ratios. Use the ContrastWithRatio class instead." @@ -474,7 +473,6 @@ class Layer(RATModel, populate_by_name=True): @classmethod def sld_imaginary_error(cls, data: Any): """If the extra input 'sld_imaginary' is given, give a more descriptive error.""" - if isinstance(data, dict) and data.get("SLD_imaginary", False): raise ValueError("The Layer class does not support imaginary SLD. Use the AbsorptionLayer class instead.") diff --git a/RATapi/outputs.py b/RATapi/outputs.py index 353459eb..053aa4cd 100644 --- a/RATapi/outputs.py +++ b/RATapi/outputs.py @@ -26,6 +26,7 @@ def get_field_string(field: str, value: Any, array_limit: int): ------- field_string : str The string representation of the field in the RAT output class. + """ array_text = "Data array: " if isinstance(value, list) and len(value) > 0: @@ -182,6 +183,7 @@ class PredictionIntervals(RATResult): The prediction interval data for SLD of each contrast. sampleChi : np.ndarray The value of sumChi at each point of the Markov chain. + """ reflectivity: list @@ -191,8 +193,7 @@ class PredictionIntervals(RATResult): @dataclass class ConfidenceIntervals(RATResult): - """ - The 65% and 95% confidence intervals for the best fit results. + """The 65% and 95% confidence intervals for the best fit results. Attributes ---------- @@ -202,6 +203,7 @@ class ConfidenceIntervals(RATResult): The 65% confidence intervals for each fit parameter. mean : np.ndarray The mean values for each fit parameter. + """ percentile95: np.ndarray diff --git a/RATapi/run.py b/RATapi/run.py index 6b158255..dee7da93 100644 --- a/RATapi/run.py +++ b/RATapi/run.py @@ -16,6 +16,7 @@ class ProgressBar: ---------- display : bool, default: True Indicates if displaying is allowed + """ def __init__(self, display=True): @@ -41,6 +42,7 @@ def updateProgress(self, event): ---------- event: ProgressEventData The progress event data. + """ if self.pbar is None: self.pbar = tqdm(**self.tqdm_kwargs) @@ -64,6 +66,7 @@ class TextOutput: ---------- display : bool, default: True Indicates if displaying is allowed + """ def __init__(self, display=True): @@ -82,6 +85,7 @@ def printMessage(self, msg): ---------- msg: str The event message. + """ print(msg, end="") diff --git a/RATapi/utils/convert.py b/RATapi/utils/convert.py index e831e905..66923448 100644 --- a/RATapi/utils/convert.py +++ b/RATapi/utils/convert.py @@ -46,7 +46,8 @@ def r1_to_project_class(filename: Union[str, PathLike]) -> Project: def zip_if_several(*params) -> Union[tuple, list[tuple]]: """Zips parameters if necessary, but can handle single-item parameters. - Examples: + Examples + -------- zip_if_several([1, 2], [3, 4]) = [(1, 3), (2, 4)] zip_if_several(1, 2, 3) = [(1, 2, 3)] @@ -79,6 +80,7 @@ def read_param(names, constrs, values, fits): ------- ClassList A list of all relevant parameters. + """ def fix_invalid_constraints(name: str, constrs: tuple[float, float], value: float) -> tuple[float, float]: @@ -334,6 +336,7 @@ def project_class_to_r1( ------- dict or None If `return_struct` is True, return the r1 struct. Else, return nothing. + """ def convert_parameters( @@ -355,6 +358,7 @@ def convert_parameters( ------- dict A dict of the relevant struct fields. + """ output = { name: [p.name for p in params], diff --git a/RATapi/utils/plotting.py b/RATapi/utils/plotting.py index 7b8c03e8..feaf010b 100644 --- a/RATapi/utils/plotting.py +++ b/RATapi/utils/plotting.py @@ -79,6 +79,7 @@ def plot_ref_sld_helper( Controls whether the grid is shown show_legend : bool, default: True Controls whether the lengend is shown + Returns ------- fig : matplotlib.pyplot.figure @@ -345,6 +346,7 @@ def plotEvent(self, event): ---------- event: PlotEventData The plot event data. + """ if not self.closed and self.figure.number in plt.get_fignums(): plot_ref_sld_helper(event, self.figure) @@ -675,6 +677,7 @@ def panel_plot_helper(plot_func: Callable, indices: list[int]) -> matplotlib.fig ------- matplotlib.figure.Figure A figure containing a grid of plots over the indices in `indices`. + """ nplots = len(indices) nrows, ncols = ceil(sqrt(nplots)), round(sqrt(nplots)) @@ -747,7 +750,6 @@ def plot_hists( If `return_fig` is True, return the figure - otherwise, return nothing. """ - # first convert names to indices if given fitname_to_index = partial(name_to_index, names=results.fitNames) diff --git a/pyproject.toml b/pyproject.toml index d20e5b8d..7993b0b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,8 +11,18 @@ line-length = 120 extend-exclude = ["*.ipynb"] [tool.ruff.lint] -select = ["E", "F", "UP", "B", "SIM", "I"] -ignore = ["SIM103", "SIM108"] +select = ["E", # pycodestyle errors + "F", # pyflakes + "UP", # pyupgrade + "B", # flake8-bugbear + "SIM", # flake8-simplify + "I", # isort + "D"] # pydocstyle + +ignore = ["SIM103", # needless bool + "SIM108", # if-else block instead of ternary operator + "D105", # undocumented __init__ + "D107"] # undocumented magic method [tool.ruff.lint.flake8-pytest-style] fixture-parentheses = false diff --git a/tests/conftest.py b/tests/conftest.py index 0b78d192..ce580c15 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6548,7 +6548,6 @@ def dream_results(): @pytest.fixture def r1_default_project(): """The Project corresponding to the data in R1defaultProject.mat.""" - project = RATapi.Project( name="defaultProject", calculation="normal", diff --git a/tests/test_classlist.py b/tests/test_classlist.py index 2a9aa881..18b75151 100644 --- a/tests/test_classlist.py +++ b/tests/test_classlist.py @@ -829,7 +829,8 @@ def test__validate_name_field(two_name_class_list: ClassList, input_dict: dict[s ) def test__validate_name_field_not_unique(two_name_class_list: ClassList, input_dict: dict[str, Any]) -> None: """We should raise a ValueError if we input values containing a name_field defined in an object in the ClassList, - accounting for case sensitivity.""" + accounting for case sensitivity. + """ with pytest.raises( ValueError, match=f"Input arguments contain the {two_name_class_list.name_field} " diff --git a/tests/test_models.py b/tests/test_models.py index aa133c79..a387dede 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -338,7 +338,6 @@ def test_contrast_bad_ratio(): @pytest.mark.filterwarnings("ignore:The following values are not recognised by this*:UserWarning") def test_type_change_clear(model): """If the type of a background or resolution is changed, it should wipe the other fields and warn the user.""" - model_instance = model( name="Test", type="constant", From b261280d8ddb0b7bd827da4c36ea3a3d370a3dd2 Mon Sep 17 00:00:00 2001 From: alexhroom Date: Tue, 18 Feb 2025 14:04:32 +0000 Subject: [PATCH 2/5] attributes -> parameters --- RATapi/outputs.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/RATapi/outputs.py b/RATapi/outputs.py index 053aa4cd..87e07e09 100644 --- a/RATapi/outputs.py +++ b/RATapi/outputs.py @@ -65,7 +65,7 @@ def __str__(self): class CalculationResults(RATResult): """The goodness of fit from the Abeles calculation. - Attributes + Parameters ---------- chiValues : np.ndarray The chi-squared value for each contrast. @@ -82,7 +82,7 @@ class CalculationResults(RATResult): class ContrastParams(RATResult): """The experimental parameters for each contrast. - Attributes + Parameters ---------- scalefactors : np.ndarray The scalefactor values for each contrast. @@ -108,7 +108,7 @@ class ContrastParams(RATResult): class Results: """The results of a RAT calculation. - Attributes + Parameters ---------- reflectivity : list The reflectivity curves for each contrast, @@ -175,7 +175,7 @@ class PredictionIntervals(RATResult): - 3: the 65th percentile; - 4: the 95th percentile. - Attributes + Parameters ---------- reflectivity : list The prediction interval data for reflectivity of each contrast. @@ -195,7 +195,7 @@ class PredictionIntervals(RATResult): class ConfidenceIntervals(RATResult): """The 65% and 95% confidence intervals for the best fit results. - Attributes + Parameters ---------- percentile95 : np.ndarray The 95% confidence intervals for each fit parameter. @@ -215,7 +215,7 @@ class ConfidenceIntervals(RATResult): class DreamParams(RATResult): """The parameters used by the inner DREAM algorithm. - Attributes + Parameters ---------- nParams : float The number of parameters used by the algorithm. @@ -286,7 +286,7 @@ class DreamParams(RATResult): class DreamOutput(RATResult): """The diagnostic output information from DREAM. - Attributes + Parameters ---------- allChains : np.ndarray An ``nGenerations`` x ``nParams + 2`` x ``nChains`` size array, @@ -337,7 +337,7 @@ class DreamOutput(RATResult): class NestedSamplerOutput(RATResult): """The output information from the Nested Sampler (ns). - Attributes + Parameters ---------- logZ : float The natural logarithm of the evidence Z for the parameter values. @@ -365,7 +365,7 @@ class NestedSamplerOutput(RATResult): class BayesResults(Results): """The results of a Bayesian RAT calculation. - Attributes + Parameters ---------- predictionIntervals : PredictionIntervals The prediction intervals. From 6776b102ac18193da270bfe2df6b86b1cc8d2a82 Mon Sep 17 00:00:00 2001 From: alexhroom Date: Tue, 18 Feb 2025 15:25:33 +0000 Subject: [PATCH 3/5] fixed all docstrings --- RATapi/__init__.py | 2 + RATapi/classlist.py | 86 ++++++++++--------- RATapi/controls.py | 6 +- RATapi/events.py | 17 ++-- RATapi/examples/__init__.py | 2 + RATapi/examples/absorption/__init__.py | 1 + RATapi/examples/absorption/absorption.py | 14 ++- .../absorption/volume_thiol_bilayer.py | 3 + .../bayes_benchmark/bayes_benchmark.py | 5 +- .../convert_rascal_project/Model_IIb.py | 3 + .../convert_rascal_project/__init__.py | 1 + .../convert_rascal_project/convert_rascal.py | 19 ++++ RATapi/examples/data/__init__.py | 1 + RATapi/examples/domains/__init__.py | 1 + RATapi/examples/domains/alloy_domains.py | 7 +- RATapi/examples/domains/domains_XY_model.py | 6 +- RATapi/examples/domains/domains_custom_XY.py | 13 ++- .../examples/domains/domains_custom_layers.py | 10 ++- .../domains/domains_standard_layers.py | 12 +++ .../examples/extras/two_contrast_example.py | 4 +- RATapi/examples/languages/__init__.py | 1 + RATapi/examples/languages/custom_bilayer.py | 3 + RATapi/examples/languages/setup_problem.py | 4 +- .../normal_reflectivity/DSPC_custom_XY.py | 4 +- .../normal_reflectivity/DSPC_custom_layers.py | 7 +- .../DSPC_data_background.py | 4 +- .../DSPC_function_background.py | 4 +- .../DSPC_standard_layers.py | 7 +- .../examples/normal_reflectivity/__init__.py | 1 + .../background_function.py | 3 + .../normal_reflectivity/custom_XY_DSPC.py | 7 +- .../custom_bilayer_DSPC.py | 4 +- RATapi/inputs.py | 39 +++++---- RATapi/models.py | 36 +++++--- RATapi/outputs.py | 23 ++++- RATapi/project.py | 36 ++++---- RATapi/run.py | 15 ++-- RATapi/utils/__init__.py | 1 + RATapi/utils/convert.py | 2 +- RATapi/utils/custom_errors.py | 8 +- RATapi/utils/enums.py | 84 ++++++++++++++++-- RATapi/utils/plotting.py | 25 +++--- RATapi/wrappers.py | 10 ++- pyproject.toml | 9 +- 44 files changed, 405 insertions(+), 145 deletions(-) diff --git a/RATapi/__init__.py b/RATapi/__init__.py index a8ce43b3..8484ea45 100644 --- a/RATapi/__init__.py +++ b/RATapi/__init__.py @@ -1,3 +1,5 @@ +"""RATapi is a Python package for modelling, fitting and optimising reflectivity problems.""" + import RATapi.examples as examples from RATapi import events, models from RATapi.classlist import ClassList diff --git a/RATapi/classlist.py b/RATapi/classlist.py index 6c050daa..c909fda4 100644 --- a/RATapi/classlist.py +++ b/RATapi/classlist.py @@ -1,6 +1,4 @@ -"""The classlist module. Contains the ClassList class, which defines a list containing instances of a particular -class. -""" +"""The ClassList class, which defines a list containing instances of a particular class.""" import collections import contextlib @@ -24,18 +22,18 @@ class ClassList(collections.UserList, Generic[T]): attribute given in the ClassList's "name_field" attribute (the default is "name"), the ClassList will ensure that all objects within the ClassList have unique values for that attribute. It is then possible to use this attribute of an object in the .remove(), .count(), and .index() routines in place of the full object. Due to the requirement - of unique values of the name_field attribute, the multiplication operators __mul__, __rmul__, and __imul__ have + of unique values of the ``name_field`` attribute, the multiplication operators __mul__, __rmul__, and __imul__ have been disabled, since they cannot allow for unique attribute values by definition. We extend the UserList class to enable objects to be added and modified using just the keyword arguments, enable - the object name_field attribute to be used in place of the full object, and ensure all elements are of the - specified type, with unique name_field attributes defined. + the object ``name_field`` attribute to be used in place of the full object, and ensure all elements are of the + specified type, with unique ``name_field`` attributes defined. Parameters ---------- init_list : Sequence [T] or T, optional An instance, or list of instance(s), of the class to be used in this ClassList. - name_field : str, optional + ``name_field`` : str, optional The field used to define unique objects in the ClassList (default is "name"). """ @@ -171,8 +169,9 @@ def __imul__(self, n: int) -> None: raise TypeError(f"unsupported operand type(s) for *=: '{self.__class__.__name__}' and '{n.__class__.__name__}'") def append(self, obj: T = None, **kwargs) -> None: - """Append a new object to the ClassList using either the object itself, or keyword arguments to set attribute - values. + """Append a new object to the ClassList. + + This method can use the object itself, or can provide attribute values as keyword arguments for a new object. Parameters ---------- @@ -184,7 +183,7 @@ def append(self, obj: T = None, **kwargs) -> None: Raises ------ ValueError - Raised if the input arguments contain a name_field value already defined in the ClassList. + Raised if the input arguments contain a ``name_field`` value already defined in the ClassList. Warnings -------- @@ -216,8 +215,9 @@ def append(self, obj: T = None, **kwargs) -> None: self.data.append(self._class_handle(**kwargs)) def insert(self, index: int, obj: T = None, **kwargs) -> None: - """Insert a new object into the ClassList at a given index using either the object itself, or keyword arguments - to set attribute values. + """Insert a new object at a given index. + + This method can use the object itself, or can provide attribute values as keyword arguments for a new object. Parameters ---------- @@ -231,7 +231,7 @@ def insert(self, index: int, obj: T = None, **kwargs) -> None: Raises ------ ValueError - Raised if the input arguments contain a name_field value already defined in the ClassList. + Raised if the input arguments contain a ``name_field`` value already defined in the ClassList. Warnings -------- @@ -263,20 +263,25 @@ def insert(self, index: int, obj: T = None, **kwargs) -> None: self.data.insert(index, self._class_handle(**kwargs)) def remove(self, item: Union[T, str]) -> None: - """Remove an object from the ClassList using either the object itself or its name_field value.""" + """Remove an object from the ClassList using either the object itself or its ``name_field`` value.""" item = self._get_item_from_name_field(item) self.data.remove(item) def count(self, item: Union[T, str]) -> int: - """Return the number of times an object appears in the ClassList using either the object itself or its - name_field value. + """Return the number of times an object appears in the ClassList. + + This method can use either the object itself or its ``name_field`` value. + """ item = self._get_item_from_name_field(item) return self.data.count(item) def index(self, item: Union[T, str], offset: bool = False, *args) -> int: - """Return the index of a particular object in the ClassList using either the object itself or its - name_field value. If offset is specified, add one to the index. This is used to account for one-based indexing. + """Return the index of a particular object in the ClassList. + + This method can use either the object itself or its ``name_field`` value. + If offset is specified, add one to the index. This is used to account for one-based indexing. + """ item = self._get_item_from_name_field(item) return self.data.index(item, *args) + int(offset) @@ -357,12 +362,12 @@ def __exit__(self, exctype, excinst, exctb): self._class_handle.model_validate(self.data[index]) def get_names(self) -> list[str]: - """Return a list of the values of the name_field attribute of each class object in the list. + """Return a list of the values of the ``name_field`` attribute of each class object in the list. Returns ------- names : list [str] - The value of the name_field attribute of each object in the ClassList. + The value of the ``name_field`` attribute of each object in the ClassList. """ return [getattr(model, self.name_field) for model in self.data if hasattr(model, self.name_field)] @@ -389,8 +394,7 @@ def get_all_matches(self, value: Any) -> list[tuple]: ] def _validate_name_field(self, input_args: dict[str, Any]) -> None: - """Raise a ValueError if the name_field attribute is passed as an object parameter, and its value is already - used within the ClassList. + """Raise a ValueError if the user tries to add an object with a ``name_field`` already in the ClassList. Parameters ---------- @@ -400,7 +404,7 @@ def _validate_name_field(self, input_args: dict[str, Any]) -> None: Raises ------ ValueError - Raised if the input arguments contain a name_field value already defined in the ClassList. + Raised if the input arguments contain a ``name_field`` value already defined in the ClassList. """ names = [name.lower() for name in self.get_names()] @@ -413,8 +417,7 @@ def _validate_name_field(self, input_args: dict[str, Any]) -> None: ) def _check_unique_name_fields(self, input_list: Sequence[T]) -> None: - """Raise a ValueError if any value of the name_field attribute is used more than once in a list of class - objects. + """Raise a ValueError if any value of the ``name_field`` attribute is repeated in a list of class objects. Parameters ---------- @@ -470,17 +473,17 @@ def _check_unique_name_fields(self, input_list: Sequence[T]) -> None: ) def _check_classes(self, input_list: Sequence[T]) -> None: - """Raise a ValueError if any object in a list of objects is not of the type specified by self._class_handle. + """Raise a ValueError if any object in a list of objects is not of the type specified by ``self._class_handle``. Parameters ---------- input_list : iterable - A list of instances of the class given in self._class_handle. + A list of instances of the class given in ``self._class_handle``. Raises ------ ValueError - Raised if the input list contains objects of any type other than that given in self._class_handle. + If the input list contains objects of any type other than that given in ``self._class_handle``. """ error_list = [] @@ -495,18 +498,18 @@ def _check_classes(self, input_list: Sequence[T]) -> None: ) def _get_item_from_name_field(self, value: Union[T, str]) -> Union[T, str]: - """Return the object with the given value of the name_field attribute in the ClassList. + """Return the object with the given value of the ``name_field`` attribute in the ClassList. Parameters ---------- value : T or str - Either an object in the ClassList, or the value of the name_field attribute of an object in the ClassList. + Either an object in the ClassList, or the value of the ``name_field`` for an object in the ClassList. Returns ------- instance : T or str - Either the object with the value of the name_field attribute given by value, or the input value if an - object with that value of the name_field attribute cannot be found. + Either the object with the value of the ``name_field`` attribute given by value, or the input value if an + object with that value of the ``name_field`` attribute cannot be found. """ try: @@ -518,24 +521,27 @@ def _get_item_from_name_field(self, value: Union[T, str]) -> Union[T, str]: @staticmethod def _determine_class_handle(input_list: Sequence[T]): - """When inputting a sequence of object to a ClassList, the _class_handle should be set as the type of the - element which satisfies "issubclass" for all the other elements. + """Determine the class handle from a sequence of objects. + + The ``_class_handle`` of the sequence is the type of the first element in the sequence + which is a subclass of all elements in the sequence. If no such element exists, the handle + is set to be the type of the first element in the list. Parameters ---------- - input_list : Sequence [object] + input_list : Sequence[T] A list of instances to populate the ClassList. Returns ------- class_handle : type - The type object of the element fulfilling the condition of satisfying "issubclass" for all of the other - elements. + The type object of the first element which is a subcalss of all of the other + elements, or the first element if no such element exists. """ - for this_element in input_list: - if all([issubclass(type(instance), type(this_element)) for instance in input_list]): - class_handle = type(this_element) + for element in input_list: + if all(issubclass(type(instance), type(element)) for instance in input_list): + class_handle = type(element) break else: class_handle = type(input_list[0]) diff --git a/RATapi/controls.py b/RATapi/controls.py index 6f7fda44..db61dfdc 100644 --- a/RATapi/controls.py +++ b/RATapi/controls.py @@ -1,3 +1,5 @@ +"""The Controls class for providing RAT algorithm settings.""" + import contextlib import os import tempfile @@ -196,14 +198,14 @@ def __str__(self) -> str: return table.get_string() def initialise_IPC(self): - """Setup the inter-process communication file.""" + """Set up the inter-process communication file.""" IPC_obj, self._IPCFilePath = tempfile.mkstemp() os.write(IPC_obj, b"0") os.close(IPC_obj) return None def sendStopEvent(self): - """Sends the stop event via the inter-process communication file. + """Send the stop event via the inter-process communication file. Warnings: -------- diff --git a/RATapi/events.py b/RATapi/events.py index e3ba19f5..c2348ecc 100644 --- a/RATapi/events.py +++ b/RATapi/events.py @@ -1,3 +1,5 @@ +"""Hooks for connecting to run callback events.""" + import os from typing import Callable, Union @@ -5,8 +7,7 @@ def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEventData]) -> None: - """Calls registered callbacks with the data when event type has - been triggered. + """Call registered callbacks with data when event type has been triggered. Parameters ---------- @@ -22,7 +23,7 @@ def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEvent def get_event_callback(event_type: EventTypes) -> list[Callable[[Union[str, PlotEventData, ProgressEventData]], None]]: - """Returns all callbacks registered for the given event type. + """Return all callbacks registered for the given event type. Parameters ---------- @@ -39,7 +40,7 @@ def get_event_callback(event_type: EventTypes) -> list[Callable[[Union[str, Plot def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventData, ProgressEventData]], None]) -> None: - """Registers a new callback for the event type. + """Register a new callback for the event type. Parameters ---------- @@ -58,12 +59,14 @@ def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventDat def clear(key=None, callback=None) -> None: - """Clears all event callbacks or specific callback. + """Clear all event callbacks or specific callback. Parameters ---------- - callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None] - The callback for when the event is triggered. + key : EventTypes, optional + The event type of the callback to clear if given. + callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None], optional + A callback for an event which will be cleared if given. """ if key is None and callback is None: diff --git a/RATapi/examples/__init__.py b/RATapi/examples/__init__.py index d2bb8877..86de2334 100644 --- a/RATapi/examples/__init__.py +++ b/RATapi/examples/__init__.py @@ -1,3 +1,5 @@ +"""Usage examples for the Python RAT API.""" + from RATapi.examples.absorption.absorption import absorption from RATapi.examples.convert_rascal_project.convert_rascal import convert_rascal from RATapi.examples.domains.domains_custom_layers import domains_custom_layers diff --git a/RATapi/examples/absorption/__init__.py b/RATapi/examples/absorption/__init__.py index e69de29b..bf48e7ae 100644 --- a/RATapi/examples/absorption/__init__.py +++ b/RATapi/examples/absorption/__init__.py @@ -0,0 +1 @@ +"""An example of using absorption in a RAT project.""" diff --git a/RATapi/examples/absorption/absorption.py b/RATapi/examples/absorption/absorption.py index ce7407d4..63b1ba3e 100644 --- a/RATapi/examples/absorption/absorption.py +++ b/RATapi/examples/absorption/absorption.py @@ -1,3 +1,5 @@ +"""An example for using absorption in RAT.""" + import pathlib import numpy as np @@ -6,7 +8,17 @@ def absorption(): - """Custom layers model including absorption""" + """Run a custom layers model including absorption. + + RAT allows the use of an imaginary, as well as real part of the SLD. + The effect of this is usually seen below the critical edge, and must sometimes be accounted for. + + This is an example of a Custom Layers project using absorption. used here is Custom Layers. + It analyses a bilayer sample on a permalloy / gold substrate, + measured using polarised neutrons, against D2O and H2O, leading to 4 contrasts in total. + Absorption (i.e. imaginary SLD) is defined for Gold and the Permalloy, + to account for non-flat data below the critical edge. + """ problem = RAT.Project( name="Absorption example", calculation="normal", diff --git a/RATapi/examples/absorption/volume_thiol_bilayer.py b/RATapi/examples/absorption/volume_thiol_bilayer.py index f64f16ff..4398f2b6 100644 --- a/RATapi/examples/absorption/volume_thiol_bilayer.py +++ b/RATapi/examples/absorption/volume_thiol_bilayer.py @@ -1,3 +1,6 @@ +"""Custom layer model file for the absorption example.""" + + def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): """VolumeThiolBilayer RAT Custom Layer Model File. diff --git a/RATapi/examples/bayes_benchmark/bayes_benchmark.py b/RATapi/examples/bayes_benchmark/bayes_benchmark.py index 1d2971b0..80ac9a24 100644 --- a/RATapi/examples/bayes_benchmark/bayes_benchmark.py +++ b/RATapi/examples/bayes_benchmark/bayes_benchmark.py @@ -1,4 +1,6 @@ -"""This example compares three Bayesian posteriors for a low-dimensional +"""An example script to compare different methods of Bayesian fitting. + +This example compares three Bayesian posteriors for a low-dimensional example: a posterior generated by DREAM, one generated by NS, and one calculated directly. @@ -33,6 +35,7 @@ # this is the RasCAL-1 default project # it is a bare D2O substrate def get_project() -> RAT.Project: + """Create the project used as our example.""" return RAT.Project( name="Bare D2O Substrate", calculation="normal", diff --git a/RATapi/examples/convert_rascal_project/Model_IIb.py b/RATapi/examples/convert_rascal_project/Model_IIb.py index ae36ba5f..d7c61526 100644 --- a/RATapi/examples/convert_rascal_project/Model_IIb.py +++ b/RATapi/examples/convert_rascal_project/Model_IIb.py @@ -1,7 +1,10 @@ +"""A custom model file for a monolayer volume model.""" + from math import cos, radians def Model_IIb(params, bulk_in, bulk_out, contrast): + """Calculate layer parameters for a monolayer volume model at two deuterations.""" # converted from matlab file Model_IIb.m Roughness, APM, thickHead, theta = params diff --git a/RATapi/examples/convert_rascal_project/__init__.py b/RATapi/examples/convert_rascal_project/__init__.py index e69de29b..0648853e 100644 --- a/RATapi/examples/convert_rascal_project/__init__.py +++ b/RATapi/examples/convert_rascal_project/__init__.py @@ -0,0 +1 @@ +"""An example of converting between RAT and RasCAL-1.""" diff --git a/RATapi/examples/convert_rascal_project/convert_rascal.py b/RATapi/examples/convert_rascal_project/convert_rascal.py index f83cb38c..b0b945f7 100644 --- a/RATapi/examples/convert_rascal_project/convert_rascal.py +++ b/RATapi/examples/convert_rascal_project/convert_rascal.py @@ -1,3 +1,5 @@ +"""An example of how to convert a RasCAL-1 project to RAT.""" + import pathlib from pprint import pp @@ -6,6 +8,23 @@ # convert R1 project to Project class def convert_rascal(mat_filename="lipid_bilayer.mat"): + """Convert a project from RasCAL-1 and a project to RasCAL-1. + + We convert a RasCAL-1 monolayer volume model to RAT, and the DSPC Standard Layers + example to RasCAL-1. + + Parameters + ---------- + mat_filename : str + The filename of the output of the RAT project converted to RasCAL-2. + + Returns + ------- + project, struct + A RasCAL-1 monolayer volume model converted to a RAT project, and the + struct of the DSPC standard layers example converted to a RasCAL-1 struct. + + """ project_path = pathlib.Path(__file__).parent / "R1monolayerVolumeModel.mat" project = RAT.utils.convert.r1_to_project_class(project_path) diff --git a/RATapi/examples/data/__init__.py b/RATapi/examples/data/__init__.py index e69de29b..9fc1b9dd 100644 --- a/RATapi/examples/data/__init__.py +++ b/RATapi/examples/data/__init__.py @@ -0,0 +1 @@ +"""Data files used by the examples.""" diff --git a/RATapi/examples/domains/__init__.py b/RATapi/examples/domains/__init__.py index e69de29b..ed955f76 100644 --- a/RATapi/examples/domains/__init__.py +++ b/RATapi/examples/domains/__init__.py @@ -0,0 +1 @@ +"""Examples for how to use RAT with domains models.""" diff --git a/RATapi/examples/domains/alloy_domains.py b/RATapi/examples/domains/alloy_domains.py index f7d9ed4c..33454dcc 100644 --- a/RATapi/examples/domains/alloy_domains.py +++ b/RATapi/examples/domains/alloy_domains.py @@ -1,5 +1,10 @@ +"""Custom model file for the domains custom layers example.""" + + def alloy_domains(params, bulkIn, bulkOut, contrast, domain): - """Simple custom model for testing incoherent summing. + """Calculate custom model layers for a permalloy/gold model with domains. + + Simple custom model for testing incoherent summing. Simple two layer of permalloy / gold, with up/down domains. """ # Split up the parameters diff --git a/RATapi/examples/domains/domains_XY_model.py b/RATapi/examples/domains/domains_XY_model.py index fd1823a4..8aeb8c77 100644 --- a/RATapi/examples/domains/domains_XY_model.py +++ b/RATapi/examples/domains/domains_XY_model.py @@ -1,9 +1,12 @@ +"""Custom model file for the domains custom XY example.""" + import math import numpy as np def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): + """Calculate the SLD profile for a domains custom XY model.""" # Split up the parameters for convenience subRough = params[0] oxideThick = params[1] @@ -51,7 +54,8 @@ def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): def makeLayer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): - """This produces a layer, with a defined thickness, height and roughness. + """Produce a layer, with a defined thickness, height and roughness. + Each side of the layer has its own roughness value. """ # Find the edges diff --git a/RATapi/examples/domains/domains_custom_XY.py b/RATapi/examples/domains/domains_custom_XY.py index e069540f..1eb7222d 100644 --- a/RATapi/examples/domains/domains_custom_XY.py +++ b/RATapi/examples/domains/domains_custom_XY.py @@ -1,10 +1,21 @@ +"""An example of using domains with a Custom XY model.""" + import pathlib import RATapi as RAT def domains_custom_XY(): - """Simple example of a layer containing domains using a custom XY model""" + """Calculate an example of a layer containing domains using a custom XY model. + + Domains custom XY models operate in the same way as domains custom layer models, + in that there is an additional input to the custom model + specifying the domain to be calculated. + + This is then used within the function to calculate the correct SLD profile + for each contrast and domain. In this example, we simulate a hydrogenated layer + on a silicon substrate, containing domains of a larger SLD, against D2O, SMW and water. + """ problem = RAT.Project(calculation="domains", model="custom xy", geometry="substrate/liquid") problem.parameters.append(name="Oxide Thickness", min=10.0, value=20.0, max=50.0, fit=True) diff --git a/RATapi/examples/domains/domains_custom_layers.py b/RATapi/examples/domains/domains_custom_layers.py index 7ebf0132..99c2d372 100644 --- a/RATapi/examples/domains/domains_custom_layers.py +++ b/RATapi/examples/domains/domains_custom_layers.py @@ -1,10 +1,18 @@ +"""An example of using domains with custom layer models.""" + import pathlib import RATapi as RAT def domains_custom_layers(): - """An example custom layers domains project involving incoherent summing on a permalloy layer""" + """Calculate an example custom layers domains project involving incoherent summing on a permalloy layer. + + For a custom layers model, rather than being forced to define our layers as [Thick SLD Rough…. etc], + we can parameterise however we like and then use a function to calculate the parameters for each layer. + So for example, if the volume of lipid tails are known (from the literature), + then all we need is the Area per molecule to calculate the layers. + """ problem = RAT.Project(calculation="domains", model="custom layers", geometry="substrate/liquid") # Make some parameters... diff --git a/RATapi/examples/domains/domains_standard_layers.py b/RATapi/examples/domains/domains_standard_layers.py index b1d08778..2da605ff 100644 --- a/RATapi/examples/domains/domains_standard_layers.py +++ b/RATapi/examples/domains/domains_standard_layers.py @@ -1,7 +1,19 @@ +"""An example using domains with standard layers.""" + import RATapi as RAT def domains_standard_layers(): + """Calculate an example for using standard layers with domains. + + Domains standard layers projects proceed in much the same way as a normal standard layers problem, + except that there is an additional grouping step between layers and contrasts. + + Layers are grouped into ‘Domain Contrasts’. + The model for the actual experimental contrast is built from these domain contrasts rather than from layers. + There are exactly two domains for each contrast, + with the the ratio of them controlled by a fittable ‘domain ratio’ parameter. + """ problem = RAT.Project(calculation="domains") # Define the parameters we need to define our two domains diff --git a/RATapi/examples/extras/two_contrast_example.py b/RATapi/examples/extras/two_contrast_example.py index 8d95f1b8..ca441e14 100644 --- a/RATapi/examples/extras/two_contrast_example.py +++ b/RATapi/examples/extras/two_contrast_example.py @@ -1,10 +1,12 @@ +"""The example project with two contrasts from the user guide.""" + import numpy as np import RATapi as RAT def two_contrast_example(): - # Two contrast example for the user guide + """Generate the two-contrast example project from the user guide.""" problem = RAT.Project(name="DSPC monolayers") parameters = [ RAT.models.Parameter(name="Tails Thickness", min=10, value=20, max=30, fit=True), diff --git a/RATapi/examples/languages/__init__.py b/RATapi/examples/languages/__init__.py index e69de29b..99fd5e1f 100644 --- a/RATapi/examples/languages/__init__.py +++ b/RATapi/examples/languages/__init__.py @@ -0,0 +1 @@ +"""A benchmark for using RAT custom files in three different languages.""" diff --git a/RATapi/examples/languages/custom_bilayer.py b/RATapi/examples/languages/custom_bilayer.py index dc978e31..1777b358 100644 --- a/RATapi/examples/languages/custom_bilayer.py +++ b/RATapi/examples/languages/custom_bilayer.py @@ -1,7 +1,10 @@ +"""A custom bilayer model for the custom file languages benchmark.""" + import numpy as np def custom_bilayer(params, bulk_in, bulk_out, contrast): + """Calculate the layer parameters for a custom bilayer model.""" sub_rough = params[0] oxide_thick = params[1] oxide_hydration = params[2] diff --git a/RATapi/examples/languages/setup_problem.py b/RATapi/examples/languages/setup_problem.py index 979c5ed1..4eea0965 100644 --- a/RATapi/examples/languages/setup_problem.py +++ b/RATapi/examples/languages/setup_problem.py @@ -1,3 +1,5 @@ +"""A custom example problem for the languages benchmark.""" + import pathlib import numpy as np @@ -6,7 +8,7 @@ def make_example_problem(): - """Custom Layers example for Supported DSPC layer. + """Generate a Custom Layers example for Supported DSPC layer. Example of using custom layers to model a DSPC supported bilayer. """ diff --git a/RATapi/examples/normal_reflectivity/DSPC_custom_XY.py b/RATapi/examples/normal_reflectivity/DSPC_custom_XY.py index ab1492da..27b15ffe 100644 --- a/RATapi/examples/normal_reflectivity/DSPC_custom_XY.py +++ b/RATapi/examples/normal_reflectivity/DSPC_custom_XY.py @@ -1,3 +1,5 @@ +"""An example of analysing a Custom XY model.""" + import pathlib import numpy as np @@ -6,7 +8,7 @@ def DSPC_custom_XY(): - r"""Custom XY Example for Supported DSPC layer. + r"""Calculate a Custom XY Example for Supported DSPC layer. In this example, we model the same data (DSPC supported bilayer) as the Custom Layers example, but this time we will use continuous distributions of the volume fractions of each component to build up the SLD profiles (as described in diff --git a/RATapi/examples/normal_reflectivity/DSPC_custom_layers.py b/RATapi/examples/normal_reflectivity/DSPC_custom_layers.py index 508653fb..66a53589 100644 --- a/RATapi/examples/normal_reflectivity/DSPC_custom_layers.py +++ b/RATapi/examples/normal_reflectivity/DSPC_custom_layers.py @@ -1,3 +1,5 @@ +"""Example of using custom layers to model a DSPC supported bilayer.""" + import pathlib import numpy as np @@ -6,10 +8,7 @@ def DSPC_custom_layers(): - """Custom Layers example for Supported DSPC layer. - - Example of using custom layers to model a DSPC supported bilayer. - """ + """Calculate a Custom Layers example for a supported DSPC layer.""" problem = RAT.Project(name="Orso lipid example - custom layers", model="custom layers", geometry="substrate/liquid") # First we need to set up a parameters group. We will be using a pre-prepared custom model file, so we need to add diff --git a/RATapi/examples/normal_reflectivity/DSPC_data_background.py b/RATapi/examples/normal_reflectivity/DSPC_data_background.py index 02987226..e4b6869f 100644 --- a/RATapi/examples/normal_reflectivity/DSPC_data_background.py +++ b/RATapi/examples/normal_reflectivity/DSPC_data_background.py @@ -1,3 +1,5 @@ +"""A standard layers example with a data background.""" + import pathlib import numpy as np @@ -6,7 +8,7 @@ def DSPC_data_background(): - """Standard Layers fit of a DSPC floating bilayer""" + """Calculate a Standard Layers fit of a DSPC floating bilayer with a data background.""" problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") # Set up the relevant parameters diff --git a/RATapi/examples/normal_reflectivity/DSPC_function_background.py b/RATapi/examples/normal_reflectivity/DSPC_function_background.py index 8a691107..54cc9d47 100644 --- a/RATapi/examples/normal_reflectivity/DSPC_function_background.py +++ b/RATapi/examples/normal_reflectivity/DSPC_function_background.py @@ -1,3 +1,5 @@ +"""A standard layers example with a function background.""" + import pathlib import numpy as np @@ -6,7 +8,7 @@ def DSPC_function_background(): - """Standard Layers fit of a DSPC floating bilayer""" + """Calculate a standard Layers fit of a DSPC floating bilayer with a function background.""" problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") # Set up the relevant parameters diff --git a/RATapi/examples/normal_reflectivity/DSPC_standard_layers.py b/RATapi/examples/normal_reflectivity/DSPC_standard_layers.py index 0d0d1181..f4cc2ce4 100644 --- a/RATapi/examples/normal_reflectivity/DSPC_standard_layers.py +++ b/RATapi/examples/normal_reflectivity/DSPC_standard_layers.py @@ -1,3 +1,5 @@ +"""An example of a standard layers model in RAT.""" + import pathlib import numpy as np @@ -6,7 +8,10 @@ def DSPC_standard_layers(): - """Standard Layers fit of a DSPC floating bilayer""" + """Calculate a standard Layers fit of a DSPC floating bilayer. + + The sample consists of a DSPC bilayer, on a silane SAM on Silicon. + """ problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") # Set up the relevant parameters diff --git a/RATapi/examples/normal_reflectivity/__init__.py b/RATapi/examples/normal_reflectivity/__init__.py index e69de29b..382a9167 100644 --- a/RATapi/examples/normal_reflectivity/__init__.py +++ b/RATapi/examples/normal_reflectivity/__init__.py @@ -0,0 +1 @@ +"""Examples of normal reflectivity calculations in RAT.""" diff --git a/RATapi/examples/normal_reflectivity/background_function.py b/RATapi/examples/normal_reflectivity/background_function.py index 68993814..43624a08 100644 --- a/RATapi/examples/normal_reflectivity/background_function.py +++ b/RATapi/examples/normal_reflectivity/background_function.py @@ -1,7 +1,10 @@ +"""A background function for an example.""" + import numpy as np def background_function(xdata, params): + """Return the background function for a given set of points in q.""" # Split up the params array Ao = params[0] k = params[1] diff --git a/RATapi/examples/normal_reflectivity/custom_XY_DSPC.py b/RATapi/examples/normal_reflectivity/custom_XY_DSPC.py index 0a8c1167..dc1d1013 100644 --- a/RATapi/examples/normal_reflectivity/custom_XY_DSPC.py +++ b/RATapi/examples/normal_reflectivity/custom_XY_DSPC.py @@ -1,10 +1,12 @@ +"""A custom XY model for a supported DSPC bilayer.""" + import math import numpy as np def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): - """This function makes a model of a supported DSPC bilayer using volume restricted distribution functions.""" + """Calculate the continuous SLD of a supported DSPC bilayer using volume restricted distribution functions.""" # Split up the parameters subRough = params[0] oxideThick = params[1] @@ -118,7 +120,8 @@ def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): def layer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): - """This produces a layer, with a defined thickness, height and roughness. + """Produce a layer, with a defined thickness, height and roughness. + Each side of the layer has its own roughness value. """ # Find the edges diff --git a/RATapi/examples/normal_reflectivity/custom_bilayer_DSPC.py b/RATapi/examples/normal_reflectivity/custom_bilayer_DSPC.py index c97cde4e..005147ff 100644 --- a/RATapi/examples/normal_reflectivity/custom_bilayer_DSPC.py +++ b/RATapi/examples/normal_reflectivity/custom_bilayer_DSPC.py @@ -1,8 +1,10 @@ +"""A custom layer model for a DSPC supported bilayer.""" + import numpy as np def custom_bilayer_DSPC(params, bulk_in, bulk_out, contrast): - """CUSTOMBILAYER RAT Custom Layer Model File. + """Calculate layer parameters for a DSPC supported bilayer. This file accepts 3 vectors containing the values for params, bulk in and bulk out. The final parameter is an index of the contrast being calculated. diff --git a/RATapi/inputs.py b/RATapi/inputs.py index d61a1901..015a81ae 100644 --- a/RATapi/inputs.py +++ b/RATapi/inputs.py @@ -1,4 +1,4 @@ -"""Converts python models to the necessary inputs for the compiled RAT code""" +"""Converts python models to the necessary inputs for the compiled RAT code.""" import importlib import os @@ -67,8 +67,8 @@ def __iter__(self): self.index = 0 return self - def get_handle(self, index): - """Returns file handle for a given custom file. + def get_handle(self, index: int): + """Return file handle for a given custom file. Parameters ---------- @@ -87,7 +87,15 @@ def get_handle(self, index): return file_handle - def copy(self): + def copy(self) -> "FileHandles": + """Create a copy of the FileHandles object. + + Returns + ------- + FileHandles + The copy of this FileHandles object. + + """ handles = FileHandles() handles.files = [file.copy() for file in self.files] @@ -106,8 +114,7 @@ def __len__(self): def make_input(project: RATapi.Project, controls: RATapi.Controls) -> tuple[ProblemDefinition, Limits, Control]: - """Constructs the inputs required for the compiled RAT code using the data defined in the input project and - controls. + """Construct the inputs required for the compiled RAT code using the data defined in the input project and controls. Parameters ---------- @@ -148,12 +155,15 @@ def make_input(project: RATapi.Project, controls: RATapi.Controls) -> tuple[Prob def make_problem(project: RATapi.Project) -> ProblemDefinition: - """Constructs the problem input required for the compiled RAT code. + """Construct the problem input required for the compiled RAT code. Parameters ---------- project : RAT.Project The project model, which defines the physical system under study. + checks : RAT.rat_core.Checks + States whether or not to fit each parameter defined in the project. + Returns ------- @@ -395,7 +405,7 @@ def make_problem(project: RATapi.Project) -> ProblemDefinition: def make_resample(project: RATapi.Project) -> list[int]: - """Constructs the "resample" field of the problem input required for the compiled RAT code. + """Construct the "resample" field of the problem input required for the compiled RAT code. Parameters ---------- @@ -404,7 +414,7 @@ def make_resample(project: RATapi.Project) -> list[int]: Returns ------- - : list[int] + list[int] The "resample" field of the problem input used in the compiled RAT code. """ @@ -412,7 +422,7 @@ def make_resample(project: RATapi.Project) -> list[int]: def make_data_present(project: RATapi.Project) -> list[int]: - """Constructs the "dataPresent" field of the problem input required for the compiled RAT code. + """Construct the "dataPresent" field of the problem input required for the compiled RAT code. Parameters ---------- @@ -421,7 +431,7 @@ def make_data_present(project: RATapi.Project) -> list[int]: Returns ------- - : list[int] + list[int] The "dataPresent" field of the problem input used in the compiled RAT code. """ @@ -429,8 +439,7 @@ def make_data_present(project: RATapi.Project) -> list[int]: def check_indices(problem: ProblemDefinition) -> None: - """Checks the indices in contrast lists in a ProblemDefinition object lie within the range of the corresponding - parameter lists. + """Check the indices a problem's contrast lists lie within the range of the corresponding parameter lists. Parameters ---------- @@ -518,14 +527,12 @@ def append_data_background(data: np.array, background: np.array) -> np.array: def make_controls(input_controls: RATapi.Controls) -> Control: - """Converts the controls object to the format required by the compiled RAT code. + """Convert the controls object to the format required by the compiled RAT code. Parameters ---------- input_controls : RAT.Controls The controls model, which defines algorithmic properties. - checks : Rat.rat_core.Checks - States whether or not to fit each parameter defined in the project. Returns ------- diff --git a/RATapi/models.py b/RATapi/models.py index 09fd8a3d..b43112d8 100644 --- a/RATapi/models.py +++ b/RATapi/models.py @@ -74,6 +74,14 @@ def __setattr__(self, name, value): @property def display_fields(self) -> dict: + """The fields which should be visible in a table and their values. + + Returns + ------- + dict + A dictionary of the fields which should be visible in a table and their values. + + """ visible_fields = ["name", "type", "source"] if self.type != TypeOptions.Constant: visible_fields.append("value_1") @@ -300,17 +308,18 @@ class CustomFile(RATModel): path: pathlib.Path = pathlib.Path(".") def model_post_init(self, __context: Any) -> None: - """If a "filename" is supplied but the "function_name" field is not set, the "function_name" should be set to - the file name without the extension. + """Autogenerate the function name from the filename if not set. + + If a filename is supplied but the ``function_name`` field is not set, the ``function_name`` should be set to + the filename without the extension. + """ if "filename" in self.model_fields_set and "function_name" not in self.model_fields_set: self.function_name = pathlib.Path(self.filename).stem @model_validator(mode="after") def set_matlab_function_name(self): - """If we have a matlab custom function, the "function_name" should be set to the filename without the - extension. - """ + """For a matlab custom function, ``function_name`` should be set to the filename without the extension.""" if self.language == Languages.Matlab and self.function_name != pathlib.Path(self.filename).stem: self.function_name = pathlib.Path(self.filename).stem @@ -339,7 +348,7 @@ class Data(RATModel, arbitrary_types_allowed=True): @field_validator("data") @classmethod def check_data_dimension(cls, data: np.ndarray[float]) -> np.ndarray[float]: - """The data must be a two-dimensional array containing at least three columns.""" + """Ensure the data is be a two-dimensional array containing at least three columns.""" try: data.shape[1] except IndexError: @@ -352,13 +361,15 @@ def check_data_dimension(cls, data: np.ndarray[float]) -> np.ndarray[float]: @field_validator("data_range", "simulation_range") @classmethod def check_min_max(cls, limits: list[float], info: ValidationInfo) -> list[float]: - """The data range and simulation range maximum must be greater than the minimum.""" + """Ensure the data range and simulation range maximum is greater than the minimum.""" if limits[0] > limits[1]: raise ValueError(f'{info.field_name} "min" value is greater than the "max" value') return limits def model_post_init(self, __context: Any) -> None: - """If the "data_range" and "simulation_range" fields are not set, but "data" is supplied, the ranges should be + """Automatically generate ``data_range`` and ``simulation_range`` from the data. + + If the ``data_range`` and ``simulation_range`` fields are not set, but ``data`` is supplied, the ranges are set to the min and max values of the first column (assumed to be q) of the supplied data. """ if self.data.shape[0] > 0: @@ -370,7 +381,9 @@ def model_post_init(self, __context: Any) -> None: @model_validator(mode="after") def check_ranges(self) -> "Data": - """The limits of the "data_range" field must lie within the range of the supplied data, whilst the limits + """Check that ``data_range`` is within the q-range of the data, and ``simulation_range`` is outside it. + + The limits of the "data_range" field must lie within the range of the supplied data, whilst the limits of the "simulation_range" field must lie outside the range of the supplied data. """ if self.data.shape[0] > 0: @@ -547,20 +560,21 @@ class Parameter(RATModel): @model_validator(mode="after") def check_min_max(self) -> "Parameter": - """The maximum value of a parameter must be greater than the minimum.""" + """Ensure the maximum value of a parameter is greater than the minimum.""" if self.min > self.max: raise ValueError(f"The maximum value {self.max} must be greater than the minimum value {self.min}") return self @model_validator(mode="after") def check_value_in_range(self) -> "Parameter": - """The value of a parameter must lie within its defined bounds.""" + """Ensure the value of a parameter lies within its defined bounds.""" if self.value < self.min or self.value > self.max: raise ValueError(f"value {self.value} is not within the defined range: {self.min} <= value <= {self.max}") return self @property def display_fields(self) -> dict: + """Only display Prior information if ``show_priors`` is true.""" visible_fields = ["name", "min", "value", "max", "fit"] if self.show_priors: visible_fields.append("prior_type") diff --git a/RATapi/outputs.py b/RATapi/outputs.py index 87e07e09..84b3222d 100644 --- a/RATapi/outputs.py +++ b/RATapi/outputs.py @@ -1,4 +1,4 @@ -"""Converts outputs from the compiled RAT code to python dataclasses""" +"""Converts results from the compiled RAT code to python dataclasses.""" from dataclasses import dataclass from typing import Any, Optional, Union @@ -10,8 +10,9 @@ def get_field_string(field: str, value: Any, array_limit: int): - """Returns a string representation of class fields where large and multidimensional arrays are represented by their - shape. + """Return a string representation of class fields where large arrays are represented by their shape. + + An array will be displayed as just its shape if it is multidimensional or 1D and longer than ``array_limit``. Parameters ---------- @@ -27,6 +28,20 @@ def get_field_string(field: str, value: Any, array_limit: int): field_string : str The string representation of the field in the RAT output class. + Examples + -------- + >>> get_field_string("data", 130, 5) + "data = 130" + + >>> get_field_string("data", array([1, 2, 3, 4, 5]), 10) + "data = [1 2 3 4 5]" + + >>> get_field_string("data", array([1, 2, 3, 4, 5]), 3) + "data = Data array: [5]," + + >>> get_field_string("data", array([[1, 2, 3], [4, 5, 6]]), 10) + "data = Data array: [2 x 3]," + """ array_text = "Data array: " if isinstance(value, list) and len(value) > 0: @@ -53,6 +68,8 @@ def get_field_string(field: str, value: Any, array_limit: int): class RATResult: + """A mixin class which truncates arrays when the class is displayed.""" + def __str__(self): output = f"{self.__class__.__name__}(\n" for key, value in self.__dict__.items(): diff --git a/RATapi/project.py b/RATapi/project.py index da36b5ed..6fcab907 100644 --- a/RATapi/project.py +++ b/RATapi/project.py @@ -358,9 +358,11 @@ def check_contrasts(cls, value: ClassList, info: ValidationInfo): return value def model_post_init(self, __context: Any) -> None: - """Initialises the class in the ClassLists for empty data fields, sets protected parameters, gets names of all - defined parameters, determines the contents of the "model" field in contrasts, and wraps ClassList routines to - control revalidation. + """Set up the Class to protect against disallowed modification. + + We initialise the class handle in the ClassLists for empty data fields, sets protected parameters, get names of + all defined parameters, determines the contents of the "model" field in contrasts, + and wraps ClassList routines to control revalidation. """ # Ensure all ClassLists have the correct _class_handle defined for field in (fields := self.model_fields): @@ -440,9 +442,7 @@ def set_domain_ratios(self) -> "Project": @model_validator(mode="after") def set_domain_contrasts(self) -> "Project": - """If we are not running a domains calculation with standard layers, ensure the domain_contrasts component of - the model is empty. - """ + """Ensure ``domain_contrasts`` is empty if we are not running a standard layer domains calculation.""" if not (self.calculation == Calculations.Domains and self.model == LayerModels.StandardLayers): self.domain_contrasts.data = [] return self @@ -487,8 +487,10 @@ def set_calculation(self) -> "Project": @model_validator(mode="after") def set_contrast_model_field(self) -> "Project": - """The contents of the "model" field of "contrasts" depend on the values of the "calculation" and "model_type" - defined in the project. If they have changed, clear the contrast models. + """Clear the contrast models if ``calculation`` or ``model_type`` has changed. + + The contents of the "model" field of "contrasts" depend on the values of the "calculation" and "model_type" + defined in the project. """ model_field = self.get_contrast_model_field() if model_field != self._contrast_model_field: @@ -499,8 +501,10 @@ def set_contrast_model_field(self) -> "Project": @model_validator(mode="after") def check_contrast_model_length(self) -> "Project": - """Given certain values of the "calculation" and "model" defined in the project, the "model" field of - "contrasts" may be constrained in its length. + """Ensure the contrast model isn't too long for a domains, custom layers, or custom XY calculation. + + If a custom model is used, the ``model`` field of the contrast should just be one item long. For + a standard layers domain calculation, it should be exactly two items long. """ if self.model == LayerModels.StandardLayers and self.calculation == Calculations.Domains: for contrast in self.contrasts: @@ -695,8 +699,7 @@ def check_contrast_model_allowed_values( allowed_values: list[str], allowed_field: str, ) -> None: - """The contents of the "model" field of "contrasts" and "domain_contrasts" must be defined elsewhere in the - project. + """Ensure the contents of the ``model`` for a contrast or domain contrast exist in the required project fields. Parameters ---------- @@ -911,7 +914,7 @@ def load(cls, path: Union[str, Path]) -> "Project": return cls.model_validate(model_dict) def _classlist_wrapper(self, class_list: ClassList, func: Callable): - """Defines the function used to wrap around ClassList routines to force revalidation. + """Define the function used to wrap around ClassList routines to force revalidation. Parameters ---------- @@ -929,8 +932,11 @@ def _classlist_wrapper(self, class_list: ClassList, func: Callable): @functools.wraps(func) def wrapped_func(*args, **kwargs): - """Run the given function and then revalidate the "Project" model. If any exception is raised, restore - the previous state of the given ClassList and report details of the exception. + """Run the given function and then revalidate the "Project" model. + + If any exception is raised, restore the previous state of the given ClassList + and report details of the exception. + """ previous_state = copy.deepcopy(class_list.data) return_value = None diff --git a/RATapi/run.py b/RATapi/run.py index dee7da93..17f47ecc 100644 --- a/RATapi/run.py +++ b/RATapi/run.py @@ -1,3 +1,5 @@ +"""The function used to run a RAT algorithm for a given project and controls.""" + import time from tqdm.auto import tqdm @@ -9,13 +11,12 @@ class ProgressBar: - """Creates a progress bar that gets updates from the progress event during a - calculation + """Create a progress bar that gets updates from the progress event during a calculation. Parameters ---------- - display : bool, default: True - Indicates if displaying is allowed + display : bool, default True + Indicates if displaying is allowed """ @@ -36,7 +37,7 @@ def __enter__(self): return self def updateProgress(self, event): - """Callback for the progress event. + """Update the progress bar with progress event data. Parameters ---------- @@ -60,7 +61,7 @@ def __exit__(self, _exc_type, _exc_val, _traceback): class TextOutput: - """Pipes the message event to stdout + """Context manager to pipe message events to stdout. Parameters ---------- @@ -79,7 +80,7 @@ def __enter__(self): return self def printMessage(self, msg): - """Callback for the message event. + """Print an event message. Parameters ---------- diff --git a/RATapi/utils/__init__.py b/RATapi/utils/__init__.py index e69de29b..f229eb5c 100644 --- a/RATapi/utils/__init__.py +++ b/RATapi/utils/__init__.py @@ -0,0 +1 @@ +"""Additional utilities for RATapi.""" diff --git a/RATapi/utils/convert.py b/RATapi/utils/convert.py index 66923448..35bc216b 100644 --- a/RATapi/utils/convert.py +++ b/RATapi/utils/convert.py @@ -348,7 +348,7 @@ def convert_parameters( ---------- params: ClassList A list of parameter type from the Project. - names, constrs, values, fits : str + name, constr, value, fit : str The keys for names, constraints, values and whether to fit for a type of parameter. number : str, optional, default "" diff --git a/RATapi/utils/custom_errors.py b/RATapi/utils/custom_errors.py index 1778841a..425cf9ef 100644 --- a/RATapi/utils/custom_errors.py +++ b/RATapi/utils/custom_errors.py @@ -9,11 +9,11 @@ def custom_pydantic_validation_error( error_list: list[pydantic_core.ErrorDetails], custom_error_msgs: Optional[dict[str, str]] = None, ) -> list[pydantic_core.ErrorDetails]: - """Run through the list of errors generated from a pydantic ValidationError, substituting the standard error for a - PydanticCustomError for a given set of error types. + """Give Pydantic errors a better custom message with extraneous information removed. - For errors that do not have a custom error message defined, we redefine them using a PydanticCustomError to remove - the url from the error message. + We substitute the standard error for a PydanticCustomError for a given set of error types. + For errors that do not have a custom error message defined, + we redefine them using a PydanticCustomError to remove the url from the error message. Parameters ---------- diff --git a/RATapi/utils/enums.py b/RATapi/utils/enums.py index dd8e8660..2f0739ae 100644 --- a/RATapi/utils/enums.py +++ b/RATapi/utils/enums.py @@ -1,3 +1,5 @@ +"""The Enum values used in the parameters of various RATapi classes and functions.""" + from typing import Union try: @@ -7,6 +9,8 @@ class RATEnum(StrEnum): + """A subclass of StrEnum with some adjustments for variable spellings.""" + @classmethod def _missing_(cls, value: str): value = value.lower() @@ -22,25 +26,39 @@ def _missing_(cls, value: str): # Controls class Procedures(RATEnum): - """Defines the available options for procedures""" + """The available options for procedures.""" Calculate = "calculate" + """Run an Abelès reflectivity calculation and calculate chi-squared to the data.""" + Simplex = "simplex" + """Run a Nelder-Mead simplex optimisation over the fit parameters.""" + DE = "de" + """Run a Differential Evolution optimisation over the fit parameters.""" + NS = "ns" + """Run Bayesian Nested Sampling over the fit parameters.""" + DREAM = "dream" + """Run the Bayesian DREAM algorithm over the fit parameters.""" class Parallel(RATEnum): - """Defines the available options for parallelization""" + """The available options for parallelisation.""" Single = "single" + """Do not parallelise.""" + Points = "points" + """Split all contrasts into groups of points, and assign a process to each group.""" + Contrasts = "contrasts" + """Assign one process to each contrast.""" class Display(RATEnum): - """Defines the available options for display""" + """The available options for terminal output.""" Off = "off" Iter = "iter" @@ -49,14 +67,29 @@ class Display(RATEnum): class Strategies(RATEnum): - """Defines the available options for differential evolution strategies""" + """The available strategies for generating base vectors in differential evolution.""" Random = "random" + """The base vector is random.""" + LocalToBest = "local to best" + """The base vector is a combination of one randomly-selected local solution + and the best solution of the previous iteration.""" + BestWithJitter = "best jitter" + """The base vector is the best solution of the previous iteration, with a small random perturbation applied.""" + RandomWithPerVectorDither = "vector dither" + """The base vector is random, with a random scaling factor applied to each mutant. + This scaling factor is different for each mutant.""" + RandomWithPerGenerationDither = "generation dither" + """The base vector is random, with a random scaling factor applied to each mutant. + This scaling factor is the same for every mutant, and randomised every generation.""" + RandomEitherOrAlgorithm = "either or" + """The base vector is randomly chosen from either a pure random mutation, + or a pure recombination of parent parameter values.""" @classmethod def _missing_(cls, value: Union[int, str]): @@ -68,60 +101,101 @@ def _missing_(cls, value: Union[int, str]): return super()._missing_(value) def __int__(self): + """Convert the DE strategy to its hardcoded index in the internal code.""" # as RAT core expects strategy as an integer return list(Strategies).index(self) + 1 class BoundHandling(RATEnum): - """Defines the available options for bound handling""" + """The available options for bound handling in DREAM.""" Off = "off" + """Allow points to be sampled out of the parameter bounds.""" + Reflect = "reflect" + """If a step passes a boundary, reflect it back across the boundary.""" + Bound = "bound" + """If a step passes a boundary, set it equal to the nearest point on the boundary.""" + Fold = "fold" + """Treat the boundary as periodic and ‘wrap the step around’ to the other side of the space.""" # Models class TypeOptions(RATEnum): + """The types of signal (``Background`` and ``Resolution``).""" + Constant = "constant" + """A uniform constant signal given by a parameter.""" + Data = "data" + """A signal given in the dataset for the contrast.""" + Function = "function" + """A signal defined by a custom function.""" class BackgroundActions(RATEnum): + """Ways that the background can be applied to the model.""" + Add = "add" Subtract = "subtract" class Languages(RATEnum): + """Language options for custom files.""" + Cpp = "cpp" Python = "python" Matlab = "matlab" class Hydration(RATEnum): + """Options for the 'hydrate with' parameter of a Layer.""" + None_ = "none" BulkIn = "bulk in" BulkOut = "bulk out" class Priors(RATEnum): + """Prior distributions for parameters.""" + Uniform = "uniform" + """A uniform distribution over the parameter range.""" + Gaussian = "gaussian" + """A Gaussian distribution centred on the parameter value, + with shape defined by ``mu`` and ``sigma`` for the parameter.""" # Project class Calculations(RATEnum): + """Types of calculations that can be performed by RAT.""" + Normal = "normal" Domains = "domains" class LayerModels(RATEnum): + """Types of layer model supported by RAT.""" + CustomLayers = "custom layers" + """The layer model is given by a custom function.""" + CustomXY = "custom xy" + """The continuous SLD of the layer model is given by a custom function.""" + StandardLayers = "standard layers" + """The layer model is given by a list of ``Layer``s or ``DomainContrast``s.""" class Geometries(RATEnum): + """Where the substrate roughness is placed.""" + AirSubstrate = "air/substrate" + """The substrate roughness is placed at the end of the stack.""" + SubstrateLiquid = "substrate/liquid" + """The substrate roughness is placed at the beginning of the stack.""" diff --git a/RATapi/utils/plotting.py b/RATapi/utils/plotting.py index feaf010b..2bc11eda 100644 --- a/RATapi/utils/plotting.py +++ b/RATapi/utils/plotting.py @@ -1,4 +1,4 @@ -"""Plots using the matplotlib library""" +"""Plot results using the matplotlib library.""" import copy from functools import partial, wraps @@ -21,7 +21,7 @@ def plot_errorbars(ax: Axes, x: np.ndarray, y: np.ndarray, err: np.ndarray, one_sided: bool, color: str): - """Plots the error bars. + """Plot the error bars. Parameters ---------- @@ -55,7 +55,7 @@ def plot_ref_sld_helper( show_grid: bool = False, show_legend: bool = True, ): - """Clears the previous plots and updates the ref and SLD plots. + """Clear the previous plots and updates the ref and SLD plots. Parameters ---------- @@ -208,7 +208,7 @@ def plot_ref_sld( show_grid: bool = False, show_legend: bool = True, ) -> Union[plt.Figure, None]: - """Plots the reflectivity and SLD profiles. + """Plot the reflectivity and SLD profiles. Parameters ---------- @@ -313,8 +313,7 @@ def plot_ref_sld( class LivePlot: - """Creates a plot that gets updates from the plot event during a - calculation + """Create a plot that gets updates from the plot event during a calculation. Parameters ---------- @@ -336,11 +335,13 @@ def __enter__(self): return self.figure def _setCloseState(self, _): - """Close event handler""" + """Close event handler.""" self.closed = True def plotEvent(self, event): - """Callback for the plot event. + """Plot the figure from plot event data. + + This is a callback for the plot event. Parameters ---------- @@ -358,7 +359,9 @@ def __exit__(self, _exc_type, _exc_val, _traceback): def assert_bayesian(name: str): - """Decorator to ensure the results passed to a function are Bayesian. + """Ensure the results passed to a function are Bayesian. + + This is a decorator. Parameters ---------- @@ -666,12 +669,14 @@ def plot_contour( def panel_plot_helper(plot_func: Callable, indices: list[int]) -> matplotlib.figure.Figure: - """Helper function for panel-based plots. + """Generate a panel-based plot from a single plot function. Parameters ---------- plot_func : Callable A function which plots one parameter on an Axes object, given its index. + indices : list[int] + The list of indices to pass into ``plot_func``. Returns ------- diff --git a/RATapi/wrappers.py b/RATapi/wrappers.py index c428c254..07d5031f 100644 --- a/RATapi/wrappers.py +++ b/RATapi/wrappers.py @@ -1,3 +1,5 @@ +"""Wrappers for the interface between RATapi and MATLAB custom files.""" + import pathlib from contextlib import suppress from typing import Callable @@ -9,12 +11,12 @@ def start_matlab(): - """Starts MATLAB asynchronously and returns a future to retrieve the engine later + """Start MATLAB asynchronously and returns a future to retrieve the engine later. Returns ------- future : matlab.engine.futureresult.FutureResult - A future used to get the actual matlab engine + A future used to get the actual matlab engine. """ future = None @@ -48,7 +50,7 @@ def __init__(self, filename: str) -> None: self.function_name = path.stem def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], tuple[ArrayLike, float]]: - """Returns a wrapper for the custom MATLAB function + """Return a wrapper for the custom MATLAB function. Returns ------- @@ -95,7 +97,7 @@ def __init__(self, filename, function_name) -> None: self.engine = RATapi.rat_core.DylibEngine(filename, function_name) def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], tuple[ArrayLike, float]]: - """Returns a wrapper for the custom dynamic library function + """Return a wrapper for the custom dynamic library function. Returns ------- diff --git a/pyproject.toml b/pyproject.toml index 7993b0b4..e317759d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,8 +22,15 @@ select = ["E", # pycodestyle errors ignore = ["SIM103", # needless bool "SIM108", # if-else block instead of ternary operator "D105", # undocumented __init__ - "D107"] # undocumented magic method + "D107", # undocumented magic method + "D203", # blank line before class docstring + "D213"] # multi line summary should start at second line [tool.ruff.lint.flake8-pytest-style] fixture-parentheses = false mark-parentheses = false + +# ignore docstring lints in the tests and install script +[tool.ruff.lint.per-file-ignores] +"tests/*" = ["D"] +"setup.py" = ["D"] From b8bf460797763fac1080d3bc19322936cf795d11 Mon Sep 17 00:00:00 2001 From: alexhroom Date: Mon, 24 Feb 2025 09:02:25 +0000 Subject: [PATCH 4/5] set convention and fix some issues --- RATapi/classlist.py | 2 +- RATapi/controls.py | 2 +- pyproject.toml | 13 +++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/RATapi/classlist.py b/RATapi/classlist.py index c909fda4..7f720402 100644 --- a/RATapi/classlist.py +++ b/RATapi/classlist.py @@ -33,7 +33,7 @@ class ClassList(collections.UserList, Generic[T]): ---------- init_list : Sequence [T] or T, optional An instance, or list of instance(s), of the class to be used in this ClassList. - ``name_field`` : str, optional + name_field : str, optional The field used to define unique objects in the ClassList (default is "name"). """ diff --git a/RATapi/controls.py b/RATapi/controls.py index db61dfdc..50f18c99 100644 --- a/RATapi/controls.py +++ b/RATapi/controls.py @@ -207,7 +207,7 @@ def initialise_IPC(self): def sendStopEvent(self): """Send the stop event via the inter-process communication file. - Warnings: + Warnings -------- UserWarning Raised if we try to delete an IPC file that was not initialised. diff --git a/pyproject.toml b/pyproject.toml index e317759d..35febb57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,11 +26,16 @@ ignore = ["SIM103", # needless bool "D203", # blank line before class docstring "D213"] # multi line summary should start at second line -[tool.ruff.lint.flake8-pytest-style] -fixture-parentheses = false -mark-parentheses = false - # ignore docstring lints in the tests and install script [tool.ruff.lint.per-file-ignores] "tests/*" = ["D"] "setup.py" = ["D"] + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.pydocstyle] +convention = "numpy" + + From 48e9485d5e9de78a6d9db5f6494d80ba1e00835c Mon Sep 17 00:00:00 2001 From: alexhroom Date: Tue, 25 Feb 2025 13:29:12 +0000 Subject: [PATCH 5/5] review fixes --- RATapi/classlist.py | 2 +- RATapi/examples/domains/domains_standard_layers.py | 8 ++++---- RATapi/inputs.py | 5 +---- RATapi/project.py | 6 +++--- RATapi/utils/enums.py | 9 ++++++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/RATapi/classlist.py b/RATapi/classlist.py index 7f720402..23e85477 100644 --- a/RATapi/classlist.py +++ b/RATapi/classlist.py @@ -535,7 +535,7 @@ def _determine_class_handle(input_list: Sequence[T]): Returns ------- class_handle : type - The type object of the first element which is a subcalss of all of the other + The type object of the first element which is a subclass of all of the other elements, or the first element if no such element exists. """ diff --git a/RATapi/examples/domains/domains_standard_layers.py b/RATapi/examples/domains/domains_standard_layers.py index 2da605ff..9e821a8d 100644 --- a/RATapi/examples/domains/domains_standard_layers.py +++ b/RATapi/examples/domains/domains_standard_layers.py @@ -9,10 +9,10 @@ def domains_standard_layers(): Domains standard layers projects proceed in much the same way as a normal standard layers problem, except that there is an additional grouping step between layers and contrasts. - Layers are grouped into ‘Domain Contrasts’. - The model for the actual experimental contrast is built from these domain contrasts rather than from layers. - There are exactly two domains for each contrast, - with the the ratio of them controlled by a fittable ‘domain ratio’ parameter. + Layers are grouped into ‘Domain Contrasts’. The model for the actual experimental contrast + is built from these domain contrasts rather than from layers. There are exactly + two domains for each contrast, with the the ratio of them controlled by + a fittable ‘domain ratio’ parameter. """ problem = RAT.Project(calculation="domains") diff --git a/RATapi/inputs.py b/RATapi/inputs.py index 015a81ae..69080636 100644 --- a/RATapi/inputs.py +++ b/RATapi/inputs.py @@ -161,9 +161,6 @@ def make_problem(project: RATapi.Project) -> ProblemDefinition: ---------- project : RAT.Project The project model, which defines the physical system under study. - checks : RAT.rat_core.Checks - States whether or not to fit each parameter defined in the project. - Returns ------- @@ -439,7 +436,7 @@ def make_data_present(project: RATapi.Project) -> list[int]: def check_indices(problem: ProblemDefinition) -> None: - """Check the indices a problem's contrast lists lie within the range of the corresponding parameter lists. + """Check the indices given in a problem's contrasts lie within the range of the corresponding parameter lists. Parameters ---------- diff --git a/RATapi/project.py b/RATapi/project.py index 6fcab907..03f31e5e 100644 --- a/RATapi/project.py +++ b/RATapi/project.py @@ -360,9 +360,9 @@ def check_contrasts(cls, value: ClassList, info: ValidationInfo): 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, sets protected parameters, get names of - all defined parameters, determines the contents of the "model" field in contrasts, - and wraps ClassList routines to control revalidation. + 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. """ # Ensure all ClassLists have the correct _class_handle defined for field in (fields := self.model_fields): diff --git a/RATapi/utils/enums.py b/RATapi/utils/enums.py index 2f0739ae..06da0b1d 100644 --- a/RATapi/utils/enums.py +++ b/RATapi/utils/enums.py @@ -101,8 +101,11 @@ def _missing_(cls, value: Union[int, str]): return super()._missing_(value) def __int__(self): - """Convert the DE strategy to its hardcoded index in the internal code.""" - # as RAT core expects strategy as an integer + """Convert the DE strategy to its hardcoded index in the internal code. + + RAT core expects strategy to be an integer, as this is how it is given to + the internal DE algorithm. + """ return list(Strategies).index(self) + 1 @@ -130,7 +133,7 @@ class TypeOptions(RATEnum): """A uniform constant signal given by a parameter.""" Data = "data" - """A signal given in the dataset for the contrast.""" + """A signal for each q-value given by a dataset.""" Function = "function" """A signal defined by a custom function."""