Repository: rhayes777/PyAutoFit (python)

Issue:
Sensitivity Mapping `unique_tag` path
In the following example:

https://github.com/Jammy2211/autofit_workspace/blob/release/scripts/features/sensitivity_mapping.py

I create a `search` with the `unique_tag=hello`:

```
search = af.DynestyStatic(
    path_prefix=path.join("features", "sensitivity_mapping", "single_gaussian"),
    unique_tag="hello",
    nlive=100,
)
```

The `unique_tag` is correctly used to set up the a folder with that word in the paths:

![image](https://github.com/user-attachments/assets/36f9bfe2-6761-4a1c-bc22-3fea33da22d7)

I then perform sensitivity mapping:

```
paths = af.DirectoryPaths(
    path_prefix=path.join("features"),
    unique_tag="hello",
    name="sensitivity_mapping",
)

sensitivity = af.Sensitivity(
    paths=paths,
    simulation_instance=simulation_instance,
    base_model=base_model,
    perturb_model=perturb_model,
    simulate_cls=Simulate(),
    base_fit_cls=BaseFit(analysis_cls=Analysis),
    perturb_fit_cls=PerturbFit(analysis_cls=Analysis),
    number_of_steps=2,
    number_of_cores=2,
)
sensitivity_result = sensitivity.run()
```

![image](https://github.com/user-attachments/assets/8ccbbadf-eded-446d-9ccb-717af42b4812)


Basically, the folder `5d41402abc4b2a76b9719d911017c592` should of been placed in the `hello` folder.

However, the `unique_tag` is not used to create the folder where the sensitivity mapping results are stored:



Pull request description:
optionally include unique tag in the output path
Resolves #1032

Note that setting the unique_tag will change the identifier


Patch:
diff --git a/autofit/non_linear/paths/abstract.py b/autofit/non_linear/paths/abstract.py
index 1129be8f4..d686a5d43 100644
--- a/autofit/non_linear/paths/abstract.py
+++ b/autofit/non_linear/paths/abstract.py
@@ -32,7 +32,7 @@ class AbstractPaths(ABC):
         parent: Optional["AbstractPaths"] = None,
         unique_tag: Optional[str] = None,
         identifier: str = None,
-        image_path_suffix : str = "",
+        image_path_suffix: str = "",
     ):
         """
         Manages the path structure for `NonLinearSearch` output, for analyses both not using and using the search
@@ -244,10 +244,11 @@ class AbstractPaths(ABC):
 
         strings = list(
             filter(
-                len,
+                None,
                 [
                     str(conf.instance.output_path),
                     str(self.path_prefix),
+                    self.unique_tag,
                     str(self.name),
                 ],
             )
diff --git a/autofit/non_linear/search/abstract_search.py b/autofit/non_linear/search/abstract_search.py
index f9e63a104..3fdb70d25 100644
--- a/autofit/non_linear/search/abstract_search.py
+++ b/autofit/non_linear/search/abstract_search.py
@@ -182,9 +182,6 @@ class NonLinearSearch(AbstractFactorOptimiser, ABC):
 
         self._logger = None
 
-        if unique_tag is not None and path_prefix is not None:
-            path_prefix = path_prefix / unique_tag
-
         self.unique_tag = unique_tag
 
         if paths:
@@ -653,10 +650,11 @@ class NonLinearSearch(AbstractFactorOptimiser, ABC):
         if not self.disable_output:
             self.logger.info(f"The output path of this fit is {self.paths.output_path}")
         else:
-            self.logger.info("Output to hard-disk disabled, input a search name to enable.")
+            self.logger.info(
+                "Output to hard-disk disabled, input a search name to enable."
+            )
 
         if not self.paths.is_complete or self.force_pickle_overwrite:
-
             if not self.disable_output:
                 self.logger.info(
                     f"Outputting pre-fit files (e.g. model.info, visualization)."
@@ -959,7 +957,6 @@ class NonLinearSearch(AbstractFactorOptimiser, ABC):
         self.iterations += self.iterations_per_update
 
         if not self.disable_output:
-
             if during_analysis:
                 self.logger.info(
                     f"""Fit Running: Updating results after {self.iterations} iterations (see output folder)."""
@@ -1054,8 +1051,8 @@ class NonLinearSearch(AbstractFactorOptimiser, ABC):
         analysis: Analysis,
         during_analysis: bool,
         samples_summary: Optional[SamplesSummary] = None,
-        instance : Optional[ModelInstance] = None,
-        paths_override : Optional[AbstractPaths] = None,
+        instance: Optional[ModelInstance] = None,
+        paths_override: Optional[AbstractPaths] = None,
         search_internal=None,
     ):
         """


Test patch:
diff --git a/test_autofit/non_linear/paths/test_paths.py b/test_autofit/non_linear/paths/test_paths.py
index ffd784988..e123e897e 100644
--- a/test_autofit/non_linear/paths/test_paths.py
+++ b/test_autofit/non_linear/paths/test_paths.py
@@ -39,7 +39,9 @@ class TestPathDecorator:
         self.assert_paths_as_expected(search.paths)
 
     def test_combination_argument(self):
-        search = af.m.MockSearch("other",)
+        search = af.m.MockSearch(
+            "other",
+        )
         search.paths = af.DirectoryPaths(name="name")
         self.assert_paths_as_expected(search.paths)
 
@@ -69,3 +71,8 @@ def test_serialize(model):
     pickled_paths = pickle.loads(pickle.dumps(paths))
 
     assert pickled_paths.model is not None
+
+
+def test_unique_tag():
+    paths = af.DirectoryPaths(unique_tag="unique_tag")
+    assert "unique_tag" in paths.output_path.parts