From ca42970547748dbb8691f39f971e56d439a275b5 Mon Sep 17 00:00:00 2001 From: James Nightingale Date: Fri, 25 Oct 2024 10:30:42 +0100 Subject: [PATCH 1/3] print --- autofit/non_linear/grid/sensitivity/__init__.py | 2 ++ autofit/non_linear/initializer.py | 1 + autofit/non_linear/result.py | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/autofit/non_linear/grid/sensitivity/__init__.py b/autofit/non_linear/grid/sensitivity/__init__.py index ad83f2065..056390132 100644 --- a/autofit/non_linear/grid/sensitivity/__init__.py +++ b/autofit/non_linear/grid/sensitivity/__init__.py @@ -141,7 +141,9 @@ def run(self) -> SensitivityResult: jobs = [] for number in range(len(self._perturb_instances)): + if self._should_bypass(number=number): + model = self.model.copy() model.perturb = self._perturb_models[number] results.append( diff --git a/autofit/non_linear/initializer.py b/autofit/non_linear/initializer.py index a0966e531..7fb99b99e 100644 --- a/autofit/non_linear/initializer.py +++ b/autofit/non_linear/initializer.py @@ -222,6 +222,7 @@ def _generate_unit_parameter_list(self, model: AbstractPriorModel) -> List[float unit_parameter_list = [] for prior in model.priors_ordered_by_id: + try: lower, upper = map(prior.unit_value_for, self.parameter_dict[prior]) value = random.uniform(lower, upper) diff --git a/autofit/non_linear/result.py b/autofit/non_linear/result.py index d146d0334..e30dec302 100644 --- a/autofit/non_linear/result.py +++ b/autofit/non_linear/result.py @@ -170,7 +170,7 @@ def model_relative(self, r: float) -> AbstractPriorModel: def model_bounded(self, b: float) -> AbstractPriorModel: """ - Returns a model where every free parameter is a `UniformPrior` with `lower_limit` and `upper_limit the previous + Returns a model where every free parameter is a `UniformPrior` with `lower_limit` and `upper_limit` the previous result's inferred maximum log likelihood parameter values minus and plus the bound `b`. For example, a previous result may infer a parameter to have a maximum log likelihood value of 2. From 52489292e2992459d3c139c9388eb8d05503a63f Mon Sep 17 00:00:00 2001 From: James Nightingale Date: Thu, 31 Oct 2024 13:54:41 +0000 Subject: [PATCH 2/3] visualizer called during sensitivity mapping --- .../non_linear/grid/sensitivity/__init__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/autofit/non_linear/grid/sensitivity/__init__.py b/autofit/non_linear/grid/sensitivity/__init__.py index c0f52490d..f6928d03e 100644 --- a/autofit/non_linear/grid/sensitivity/__init__.py +++ b/autofit/non_linear/grid/sensitivity/__init__.py @@ -28,6 +28,7 @@ def __init__( base_fit_cls: Callable, perturb_fit_cls: Callable, job_cls: ClassVar = Job, + visualizer_cls: Optional[Callable] = None, perturb_model_prior_func: Optional[Callable] = None, number_of_steps: Union[Tuple[int, ...], int] = 4, mask: Optional[List[bool]] = None, @@ -62,6 +63,9 @@ def __init__( The class which fits the base model to each simulated dataset of the sensitivity map. perturb_fit_cls The class which fits the perturb model to each simulated dataset of the sensitivity map. + visualizer_cls + A class which can be used to visualize the results of the sensitivity mapping after each fit is performed, + therefore providing visualization on the fly. number_of_steps The number of steps for each dimension of the sensitivity grid. If input as a float the dimensions are all that value. If input as a tuple of length the number of dimensions, each tuple value is the number of @@ -97,6 +101,7 @@ def __init__( self.perturb_model_prior_func = perturb_model_prior_func self.job_cls = job_cls + self.visualizer_cls = visualizer_cls self.number_of_steps = number_of_steps self.mask = None @@ -165,6 +170,18 @@ def run(self) -> SensitivityResult: results.append(result) results = sorted(results) + sensitivity_result = SensitivityResult( + samples=[result.result.samples_summary for result in results], + perturb_samples=[ + result.perturb_result.samples_summary for result in results + ], + shape=self.shape, + path_values=self.path_values, + ) + + if self.visualizer_cls is not None: + self.visualizer_cls(sensitivity_result=sensitivity_result, paths=self.paths) + os.makedirs(self.paths.output_path, exist_ok=True) write_table( @@ -181,6 +198,8 @@ def run(self) -> SensitivityResult: filename=self.results_path, ) + # TODO : Had to repeat this code block to get certain unit tests to pass which presumably bypass run_jobs. + sensitivity_result = SensitivityResult( samples=[result.result.samples_summary for result in results], perturb_samples=[ From b46d116892c7fcd240ad7e812bc8c9d9a0060d95 Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 1 Nov 2024 07:14:08 +0000 Subject: [PATCH 3/3] use masked results to ensure sensitivity result list always same lenght --- .../non_linear/grid/sensitivity/__init__.py | 27 +++++++++---------- .../test_masked_sensitivity.py | 8 ++++++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/autofit/non_linear/grid/sensitivity/__init__.py b/autofit/non_linear/grid/sensitivity/__init__.py index f6928d03e..0706e384a 100644 --- a/autofit/non_linear/grid/sensitivity/__init__.py +++ b/autofit/non_linear/grid/sensitivity/__init__.py @@ -147,18 +147,16 @@ def run(self) -> SensitivityResult: jobs = [] for number in range(len(self._perturb_instances)): - - if self._should_bypass(number=number): - - model = self.model.copy() - model.perturb = self._perturb_models[number] - results.append( - MaskedJobResult( - number=number, - model=model, - ) + model = self.model.copy() + model.perturb = self._perturb_models[number] + results.append( + MaskedJobResult( + number=number, + model=model, ) - else: + ) + + if not self._should_bypass(number=number): jobs.append(self._make_job(number)) for result in process_class.run_jobs( @@ -167,8 +165,7 @@ def run(self) -> SensitivityResult: if isinstance(result, Exception): raise result - results.append(result) - results = sorted(results) + results[result.number] = result sensitivity_result = SensitivityResult( samples=[result.result.samples_summary for result in results], @@ -180,7 +177,9 @@ def run(self) -> SensitivityResult: ) if self.visualizer_cls is not None: - self.visualizer_cls(sensitivity_result=sensitivity_result, paths=self.paths) + self.visualizer_cls( + sensitivity_result=sensitivity_result, paths=self.paths + ) os.makedirs(self.paths.output_path, exist_ok=True) diff --git a/test_autofit/non_linear/grid/test_sensitivity/test_masked_sensitivity.py b/test_autofit/non_linear/grid/test_sensitivity/test_masked_sensitivity.py index bf9c33314..ed90f1822 100644 --- a/test_autofit/non_linear/grid/test_sensitivity/test_masked_sensitivity.py +++ b/test_autofit/non_linear/grid/test_sensitivity/test_masked_sensitivity.py @@ -69,3 +69,11 @@ def test_perturbed_physical_centres_list_from(masked_result): 0.75, 0.75, ] + + +def test_visualise(sensitivity): + def visualiser(sensitivity_result, **_): + assert len(sensitivity_result.samples) == 8 + + sensitivity.visualizer_cls = visualiser + sensitivity.run()