diff --git a/WeatherRoutingTool/algorithms/genetic/__init__.py b/WeatherRoutingTool/algorithms/genetic/__init__.py index f150e3f9..f04e2ae1 100644 --- a/WeatherRoutingTool/algorithms/genetic/__init__.py +++ b/WeatherRoutingTool/algorithms/genetic/__init__.py @@ -158,6 +158,13 @@ def terminate(self, res: Result, problem: RoutingProblem): """Genetic Algorithm termination procedures""" super().terminate() + + + # 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) 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): 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