From e0b4fc9a9a4bc479560a9aa06d33b57b9e00b417 Mon Sep 17 00:00:00 2001 From: Shreya Desai Date: Tue, 24 Mar 2026 08:11:41 +0530 Subject: [PATCH 1/3] Fix: handle genetic module crash with updated logic --- WeatherRoutingTool/algorithms/genetic/__init__.py | 6 +++++- WeatherRoutingTool/algorithms/genetic/population.py | 11 +++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/WeatherRoutingTool/algorithms/genetic/__init__.py b/WeatherRoutingTool/algorithms/genetic/__init__.py index f150e3f9..1ddddb3a 100644 --- a/WeatherRoutingTool/algorithms/genetic/__init__.py +++ b/WeatherRoutingTool/algorithms/genetic/__init__.py @@ -158,7 +158,11 @@ def terminate(self, res: Result, problem: RoutingProblem): """Genetic Algorithm termination procedures""" super().terminate() - + + if res is None or res.F is None or res.X is None: + raise ValueError( + "No feasible solution found, all candidates violated constraints. Please rerun." + ) best_index = res.F.argmin() # ensure res.X is of shape (n_sol, n_var) best_route = np.atleast_2d(res.X)[best_index, 0] diff --git a/WeatherRoutingTool/algorithms/genetic/population.py b/WeatherRoutingTool/algorithms/genetic/population.py index df646d01..55c5a8d5 100644 --- a/WeatherRoutingTool/algorithms/genetic/population.py +++ b/WeatherRoutingTool/algorithms/genetic/population.py @@ -205,8 +205,15 @@ def generate(self, problem, n_samples, **kw): # fallback: fill all other individuals with the same population as the last one for j in range(i + 1, n_samples): - X[j, 0] = np.copy(X[j - 1, 0]) - return X + route = np.copy(X[j - 1, 0]) + + noise = np.random.normal( + loc=0, + scale=0.01, + size=route.shape + ) + + X[j, 0] = route + noise class GcrSliderPopulation(Population): From 7cf36c5665904c6e99492130617ce8da78b5bcf4 Mon Sep 17 00:00:00 2001 From: Shreya Desai Date: Tue, 24 Mar 2026 09:38:46 +0530 Subject: [PATCH 2/3] Fix: handle case when no feasible solution exists in Genetic.terminate() --- WeatherRoutingTool/algorithms/genetic/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/WeatherRoutingTool/algorithms/genetic/__init__.py b/WeatherRoutingTool/algorithms/genetic/__init__.py index 1ddddb3a..f04e2ae1 100644 --- a/WeatherRoutingTool/algorithms/genetic/__init__.py +++ b/WeatherRoutingTool/algorithms/genetic/__init__.py @@ -159,10 +159,13 @@ def terminate(self, res: Result, problem: RoutingProblem): super().terminate() - if res is None or res.F is None or res.X is None: - raise ValueError( - "No feasible solution found, all candidates violated constraints. Please rerun." + + # Inside Genetic.terminate() + if res is None or res.F is None or res.X is None or len(res.F) == 0: + raise ValueError( + "No feasible solution found. All candidates violated constraints. Please rerun with relaxed constraints." ) + best_index = res.F.argmin() # ensure res.X is of shape (n_sol, n_var) best_route = np.atleast_2d(res.X)[best_index, 0] From 1d49109c08bea152a2b32c032250de3e5dc09637 Mon Sep 17 00:00:00 2001 From: Shreya Desai Date: Tue, 24 Mar 2026 19:45:55 +0530 Subject: [PATCH 3/3] Fix: prevent NaN in apparent wind calculation with edge values --- tests/test_direct_power_method.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_direct_power_method.py b/tests/test_direct_power_method.py index dd85f739..1ead2003 100644 --- a/tests/test_direct_power_method.py +++ b/tests/test_direct_power_method.py @@ -358,3 +358,15 @@ def test_valid_parameters(self): except ValueError: # If we get here, there was an unexpected ValueError assert False, "Valid parameters should not raise ValueError" + def test_get_apparent_wind_no_nan_with_edge_values(self): + wind_dir = np.array([0, 90, 180]) * u.degree + + # slightly tricky values to trigger floating precision issues + wind_speed = np.array([10, 10, 10]) * u.meter / u.second + + pol = basic_test_func.create_dummy_Direct_Power_Ship('simpleship') + wind_result = pol.get_apparent_wind(wind_speed, wind_dir) + + # check no NaN in outputs + assert not np.isnan(wind_result['app_wind_speed']).any() + assert not np.isnan(wind_result['app_wind_angle']).any() \ No newline at end of file