Skip to content

Commit 3f787fe

Browse files
committed
update gitignore, refactor pymoo pymoode implementation, fix mop factory
1 parent 1f363cd commit 3f787fe

File tree

3 files changed

+51
-24
lines changed

3 files changed

+51
-24
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
## private stuff
66
.results/
7+
test_data/result
8+
test_data/01_WorldPositions_selection.csv
79
.tmp/
810
dist/
911
## data

carmodel_calibration/control_program/calibration_handling.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,7 @@ def _run_optimization(self, bounds, sumo_interface, identification):
303303
ITERATION = 1
304304
self.iteration_results = []
305305
self.all_iteration_results = []
306-
self._prepare_optimization(
307-
sumo_interface, identification)
306+
self._prepare_optimization(sumo_interface, identification)
308307
START_TIME = time.time()
309308
if self._optimization == "differential_evolution":
310309
self.initial_population = random_population_from_bounds(
@@ -372,7 +371,7 @@ def _run_optimization(self, bounds, sumo_interface, identification):
372371
# mutation_probability=[0.33, 0.10], # for adaptive
373372
mutation_probability=self.mutation_probability,
374373
save_best_solutions=True,
375-
on_fitness=fitness_callback_factory(self))
374+
on_fitness=fitness_callback_factory(self, "pygad"))
376375
ga_instance.run()
377376
solution, solution_fitness, _ = (
378377
ga_instance.best_solution())
@@ -421,7 +420,7 @@ def _run_optimization(self, bounds, sumo_interface, identification):
421420
# mutation_probability=[0.33, 0.10], # for adaptive
422421
mutation_probability=self.mutation_probability,
423422
save_best_solutions=True,
424-
on_fitness=fitness_callback_factory_nsga2(self))
423+
on_fitness=fitness_callback_factory(self, "pymoo"))
425424
nsga_instance.run()
426425
solution, solution_fitness, _ = (
427426
nsga_instance.best_solution())
@@ -532,10 +531,17 @@ def _prepare_optimization(self, sumo_interface, identification):
532531
"timestep": self.timestep,
533532
"project_path": self.project_path
534533
}
534+
# by default, the mops's are reduced to a single value, except for the
535+
# optimization algorithms that explicitly handle mulitple measures of performance
536+
# by themselves
537+
reduce = True
538+
if self._optimization in ["nsga2", "gde3", "nsde"]:
539+
reduce = False
535540
objective_function = {
536541
"identification": identification,
537542
"objectives": self.objectives,
538543
"weights": self.weights,
544+
"reduce_mmop2smop": reduce,
539545
"gof": self.gof}
540546
data = {
541547
"identification": identification,
@@ -665,11 +671,11 @@ def random_population_from_bounds(bounds: tuple, population_size: int,
665671
return population
666672

667673

668-
def fitness_callback_factory(item):
674+
def fitness_callback_factory(item, module_name):
669675
"""a factory for the fitness callback function"""
670676

671-
def on_fitness(ga_instance: pygad.GA, solutions):
672-
"""provided callback for fitness"""
677+
def on_fitness_pygad(ga_instance: pygad.GA, solutions):
678+
"""provided callback for fitness on pygad iteration"""
673679
best_solution = ga_instance.best_solutions[-1]
674680
best = np.max(ga_instance.last_generation_fitness)
675681
if best < np.max(solutions):
@@ -679,15 +685,10 @@ def on_fitness(ga_instance: pygad.GA, solutions):
679685
# TODO: log instead of 1 / 0
680686
kwargs = {"weighted_error": 1 / best}
681687
_ = item.log_iteration(best_solution, **kwargs)
682-
return on_fitness
683688

684-
685-
def fitness_callback_factory_nsga2(item):
686-
"""a factory for the fitness callback function"""
687-
688-
def on_fitness(nsga_instance: pygad.GA, solutions_fitness):
689-
"""provided callback for fitness"""
690-
solution, solution_fitness, _ = (
689+
def on_fitness_pymoo(nsga_instance, solutions_fitness):
690+
"""provided callback for fitness for pymoo iteration"""
691+
_, solution_fitness, _ = (
691692
nsga_instance.best_solution(nsga_instance.last_generation_fitness))
692693
best_solution = nsga_instance.best_solutions[-1]
693694
best = np.sum([1 / sol for sol in solution_fitness])
@@ -702,4 +703,11 @@ def on_fitness(nsga_instance: pygad.GA, solutions_fitness):
702703
kwargs = {"weighted_error": best,
703704
"nondom": pareto[0], "pop": nsga_instance.population}
704705
_ = item.log_iteration(best_solution, **kwargs)
705-
return on_fitness
706+
707+
if module_name == "pygad":
708+
return on_fitness_pygad
709+
elif module_name == "pymoo":
710+
return on_fitness_pymoo
711+
else:
712+
return NotImplementedError("Module not implemented")
713+

carmodel_calibration/optimization.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717

1818
def measure_of_performance_factory(objectives=["distance"],
19-
weights=None, gof="rmse", **__):
19+
weights=None, gof="rmse", reduce_mmop2smop=True,
20+
**__):
2021
"""
2122
this function will return the appropiate objective function handle
2223
depending on the desired MOP and the calibration object
@@ -73,7 +74,10 @@ def rmse(ground_truth, prediction):
7374
prediction[sop].values
7475
- ground_truth[sop].values))
7576
sums[idx] = np.sqrt(sums[idx] / len(ground_truth)) * weights[sop]
76-
return np.sum(sums)
77+
if reduce_mmop2smop:
78+
return np.sum(sums)
79+
else:
80+
return sums
7781

7882
def nrmse(ground_truth, prediction):
7983
"""
@@ -90,7 +94,10 @@ def nrmse(ground_truth, prediction):
9094
gt_root = np.sqrt(np.sum(np.square(ground_truth[sop].values))
9195
/ len(ground_truth))
9296
sums[idx] = rmse_error / (gt_root) * weights[sop]
93-
return sums
97+
if reduce_mmop2smop:
98+
return np.sum(sums)
99+
else:
100+
return sums
94101

95102
def rmspe(ground_truth, prediction):
96103
"""
@@ -105,7 +112,10 @@ def rmspe(ground_truth, prediction):
105112
- ground_truth[sop].values)
106113
/ ground_truth[sop].values))
107114
sums[idx] = np.sqrt(sums[idx] / len(ground_truth)) * weights[sop]
108-
return np.sum(sums)
115+
if reduce_mmop2smop:
116+
return np.sum(sums)
117+
else:
118+
return sums
109119

110120
def theils_u(ground_truth, prediction):
111121
"""
@@ -124,16 +134,23 @@ def theils_u(ground_truth, prediction):
124134
gt_root = np.sqrt(np.sum(np.square(ground_truth[sop].values))
125135
/ len(ground_truth))
126136
sums[idx] = rmse_error / (sim_root + gt_root) * weights[sop]
127-
return np.sum(sums)
137+
if reduce_mmop2smop:
138+
return np.sum(sums)
139+
else:
140+
return sums
128141

129142
def model_output(_, prediction):
130143
"""only sum model outputs"""
131144
sums = np.zeros(len(objectives))
132145
for idx, sop in enumerate(objectives):
133146
sums[idx] = prediction[sop].values[-1] * weights[sop]
134-
return np.sum(sums)
135-
gof_handles = {"rmse": rmse, "nrmse": nrmse, "rmsep": rmspe, "modelOutput": model_output,
136-
"theils_u": theils_u}
147+
if reduce_mmop2smop:
148+
return np.sum(sums)
149+
else:
150+
return sums
151+
152+
gof_handles = {"rmse": rmse, "nrmse": nrmse, "rmsep": rmspe,
153+
"modelOutput": model_output, "theils_u": theils_u}
137154

138155
def get_weighted_error(ground_truth, prediction):
139156
"""calculate weighted error on case1"""

0 commit comments

Comments
 (0)