Index: framspy/evolalg/examples/niching_novelty.py
===================================================================
--- framspy/evolalg/examples/niching_novelty.py	(revision 1138)
+++ framspy/evolalg/examples/niching_novelty.py	(revision 1139)
@@ -1,3 +1,4 @@
 import argparse
+import logging
 import os
 import pickle
@@ -22,4 +23,5 @@
 from evolalg.statistics.statistics_deap import StatisticsDeap
 from evolalg.base.union_step import UnionStep
+from evolalg.utils.name_propagation import propagate_names
 from evolalg.utils.population_save import PopulationSave
 import time
@@ -58,14 +60,15 @@
                         help='optimization criteria : vertpos, velocity, distance, vertvel, lifespan, numjoints, numparts, numneurons, numconnections (or other as long as it is provided by the .sim file and its .expdef). Single or multiple criteria.')
     parser.add_argument('-lib', required=False, help="Filename of .so or .dll with the Framsticks library")
+
     parser.add_argument('-genformat', required=False, default="1",
                         help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')
     parser.add_argument('-sim', required=False, default="eval-allcriteria.sim", help="Name of the .sim file with all parameter values")
+    parser.add_argument('-fit', required=False, default=Fitness.raw, type=Fitness,
+                        help=' Fitness criteria, default: raw', choices=list(Fitness))
     parser.add_argument('-dissim', required=False, type=Dissim, default=Dissim.frams,
-                        help='Dissimilarity measure, default = frams', choices=list(Dissim))
-    parser.add_argument('-fit', required=False, default=Fitness.raw, type=Fitness,
-                        help=' Fitness criteria, default = raw', choices=list(Fitness))
-    parser.add_argument('-popsize', type=int, default=50, help="Population size, default 50.")
-    parser.add_argument('-generations', type=int, default=5, help="Number of generations, default 5.")
-    parser.add_argument('-tournament', type=int, default=5, help="Tournament size, default 5.")
+                        help='Dissimilarity measure, default: frams', choices=list(Dissim))
+    parser.add_argument('-popsize', type=int, default=50, help="Population size, default: 50.")
+    parser.add_argument('-generations', type=int, default=5, help="Number of generations, default: 5.")
+    parser.add_argument('-tournament', type=int, default=5, help="Tournament size, default: 5.")
 
     parser.add_argument('-max_numparts', type=int, default=None, help="Maximum number of Parts. Default: no limit")
@@ -74,6 +77,9 @@
     parser.add_argument('-max_numconnections', type=int, default=None, help="Maximum number of Neural connections. Default: no limit")
 
+    parser.add_argument('-hof_evaluations', type=int, default=20, help="Number of final evaluations of each genotype in Hall of Fame to obtain reliable (averaged) fitness. Default: 20.")
     parser.add_argument('-checkpoint_path', required=False, default=None, help="Path to the checkpoint file")
     parser.add_argument('-checkpoint_interval', required=False, type=int, default=100, help="Checkpoint interval")
+    parser.add_argument('--debug', dest='debug', action='store_true', help="Prints names of steps as they are executed")
+    parser.set_defaults(debug=False)
     return parser.parse_args()
 
@@ -123,4 +129,11 @@
         return individual.numconnections > self.max_number
 
+class ReplaceWithHallOfFame(Step):
+    def __init__(self, hof, *args, **kwargs):
+        super(ReplaceWithHallOfFame, self).__init__(*args, **kwargs)
+        self.hof = hof
+    def call(self, population, *args, **kwargs):
+        super(ReplaceWithHallOfFame, self).call(population)
+        return list(self.hof.halloffame)
 
 def func_niching(ind): setattr(ind, "fitness", ind.fitness_raw * (1 + ind.dissim))
@@ -173,7 +186,8 @@
                               evaluation_count=1)
 
+
     fitness_end = FitnessStep(frams_lib, fields={parsed_args.opt: "fitness_raw"},
                               fields_defaults={parsed_args.opt: None},
-                              evaluation_count=100)  # evaluate the contents of the last population 100 times (TODO replace this approach and evaluate HOF instead of the last population)
+                              evaluation_count=parsed_args.hof_evaluations)
     # Remove
     remove = []
@@ -230,4 +244,5 @@
     # Statistics
     hall_of_fame = HallOfFameStatistics(100, "fitness_raw")  # Wrapper for halloffamae
+    replace_with_hof = ReplaceWithHallOfFame(hall_of_fame)
     statistics_deap = StatisticsDeap([
         ("avg", np.mean),
@@ -248,4 +263,5 @@
     # End stages: this will execute exacly once after all generations.
     end_stages = [
+        replace_with_hof,
         fitness_end,
         PopulationSave("halloffame.gen", provider=hall_of_fame.halloffame, fields={"genotype": "genotype",
@@ -254,5 +270,9 @@
 
     # -------------------------------------------------
+
+
+
     # Experiment creation
+
 
     experiment = Experiment(init_population=init_stages,
@@ -271,4 +291,6 @@
     print("Running experiment with", sys.argv)
     parsed_args = parseArguments()
+    if parsed_args.debug:
+        logging.basicConfig(level=logging.DEBUG)
 
     if parsed_args.checkpoint_path is not None and os.path.exists(parsed_args.checkpoint_path):
@@ -301,3 +323,4 @@
 
 if __name__ == '__main__':
+
     main()
