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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion EasyReflectometryApp/Backends/Py/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ def load(self, paths: str) -> None:
paths = paths.split(',')

for path in paths:
self._project_logic.load_new_experiment(IO.generalizePath(path))
generalized = IO.generalizePath(path)
if self._project_logic.count_datasets_in_file(generalized) > 1:
self._project_logic.load_all_experiments_from_file(generalized)
else:
self._project_logic.load_new_experiment(generalized)
self.experimentChanged.emit()
self.externalExperimentChanged.emit()
pass # debug anchor
37 changes: 22 additions & 15 deletions EasyReflectometryApp/Backends/Py/logic/fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,25 +161,32 @@ def prepare_threaded_fit(self, minimizers_logic: 'Minimizers') -> tuple:
if minimizers_logic.max_iterations is not None:
multi_fitter.easy_science_multi_fitter.max_evaluations = minimizers_logic.max_iterations

# Prepare data arrays for all experiments
x_data = [experiment.x for experiment in experiments]
y_data = [experiment.y for experiment in experiments]

# Validate error values before computing weights to avoid division by zero
# Prepare data arrays for all experiments, masking out zero-variance points
import numpy as np

x_data = []
y_data = []
weights = []
for idx, experiment in enumerate(experiments):
ye = experiment.ye
if np.any(ye == 0):
x_vals = np.asarray(experiment.x)
y_vals = np.asarray(experiment.y)
ye_vals = np.asarray(experiment.ye)

# Mask out points with zero variance (same as MultiFitter.fit in EasyReflectometryLib)
valid = ye_vals > 0
num_masked = int(np.sum(~valid))
if num_masked > 0:
exp_name = experiment.name if hasattr(experiment, 'name') else f'index {idx}'
self._fit_error_message = f'Experiment {exp_name} has zero error values which would cause division by zero'
self._running = False
self._finished = True
self._show_results_dialog = True
return None, None, None, None, None

# ye contains variances (sigma²); weights = 1/sigma = 1/sqrt(variance)
weights = [1.0 / np.sqrt(experiment.ye) for experiment in experiments]
logger.warning(
'Masked %d data point(s) in experiment %s due to zero variance.',
num_masked,
exp_name,
)

x_data.append(x_vals[valid])
y_data.append(y_vals[valid])
# ye contains variances (sigma²); weights = 1/sigma = 1/sqrt(variance)
weights.append(1.0 / np.sqrt(ye_vals[valid]))

# Method is optional in fit() - pass None to use minimizer's default
method = None
Expand Down
6 changes: 6 additions & 0 deletions EasyReflectometryApp/Backends/Py/logic/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ def load_experiment(self, path: str) -> None:
def load_new_experiment(self, path: str) -> None:
self._project_lib.load_new_experiment(path)

def count_datasets_in_file(self, path: str) -> int:
return self._project_lib.count_datasets_in_file(path)

def load_all_experiments_from_file(self, path: str) -> int:
return self._project_lib.load_all_experiments_from_file(path)

def set_sample_from_orso(self, sample) -> None:
self._project_lib.set_sample_from_orso(sample)

Expand Down
70 changes: 37 additions & 33 deletions EasyReflectometryApp/Backends/Py/plotting_1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,22 +515,23 @@ def getExperimentDataPoints(self, experiment_index: int) -> list:
data = self._project_lib.experimental_data_for_model_at_index(experiment_index)
points = []
for point in data.data_points():
if point[0] < self._project_lib.q_max and self._project_lib.q_min < point[0]:
q = point[0]
r = point[1]
error_var = point[2]
error_lower_linear = max(r - np.sqrt(error_var), 1e-10)
r_val = self._apply_rq4(q, r)
error_upper = self._apply_rq4(q, r + np.sqrt(error_var))
error_lower = self._apply_rq4(q, error_lower_linear)
points.append(
{
'x': float(q),
'y': float(np.log10(r_val)),
'errorUpper': float(np.log10(error_upper)),
'errorLower': float(np.log10(error_lower)),
}
)
q = point[0]
r = point[1]
if r <= 0:
continue
error_var = point[2]
error_lower_linear = max(r - np.sqrt(error_var), 1e-10)
r_val = self._apply_rq4(q, r)
error_upper = self._apply_rq4(q, r + np.sqrt(error_var))
error_lower = self._apply_rq4(q, error_lower_linear)
points.append(
{
'x': float(q),
'y': float(np.log10(r_val)),
'errorUpper': float(np.log10(error_upper)),
'errorLower': float(np.log10(error_lower)),
}
)
return points
except Exception as e:
console.debug(f'Error getting experiment data points for index {experiment_index}: {e}')
Expand Down Expand Up @@ -678,18 +679,19 @@ def qtchartsReplaceMeasuredOnExperimentChartAndRedraw(self):
series_error_lower.clear()
nr_points = 0
for point in self.experiment_data.data_points():
if point[0] < self._project_lib.q_max and self._project_lib.q_min < point[0]:
q = point[0]
r = point[1]
error_var = point[2]
error_lower_linear = max(r - np.sqrt(error_var), 1e-10)
r_val = self._apply_rq4(q, r)
error_upper = self._apply_rq4(q, r + np.sqrt(error_var))
error_lower = self._apply_rq4(q, error_lower_linear)
series_measured.append(q, np.log10(r_val))
series_error_upper.append(q, np.log10(error_upper))
series_error_lower.append(q, np.log10(error_lower))
nr_points = nr_points + 1
q = point[0]
r = point[1]
if r <= 0:
continue
error_var = point[2]
error_lower_linear = max(r - np.sqrt(error_var), 1e-10)
r_val = self._apply_rq4(q, r)
error_upper = self._apply_rq4(q, r + np.sqrt(error_var))
error_lower = self._apply_rq4(q, error_lower_linear)
series_measured.append(q, np.log10(r_val))
series_error_upper.append(q, np.log10(error_upper))
series_error_lower.append(q, np.log10(error_lower))
nr_points = nr_points + 1

console.debug(IO.formatMsg('sub', 'Measured curve', f'{nr_points} points', 'on experiment page', 'replaced'))

Expand Down Expand Up @@ -738,11 +740,13 @@ def qtchartsReplaceCalculatedAndMeasuredOnAnalysisChartAndRedraw(self):
series_calculated.clear()
nr_points = 0
for point in self.experiment_data.data_points():
if point[0] < self._project_lib.q_max and self._project_lib.q_min < point[0]:
q = point[0]
r_meas = self._apply_rq4(q, point[1])
series_measured.append(q, np.log10(r_meas))
nr_points = nr_points + 1
q = point[0]
r_meas = point[1]
if r_meas <= 0:
continue
r_meas = self._apply_rq4(q, r_meas)
series_measured.append(q, np.log10(r_meas))
nr_points = nr_points + 1
console.debug(IO.formatMsg('sub', 'Measured curve', f'{nr_points} points', 'on analysis page', 'replaced'))

for point in self.model_data.data_points():
Expand Down