Index: framspy/evolalg/base/experiment_abc.py
===================================================================
--- framspy/evolalg/base/experiment_abc.py	(revision 1283)
+++ framspy/evolalg/base/experiment_abc.py	(revision 1289)
@@ -23,7 +23,7 @@
     current_generation = 0
     time_elapsed = 0
-    
-
-    def __init__(self, popsize, hof_size, save_only_best=True) -> None:
+
+
+    def __init__(self, popsize, hof_size, save_only_best) -> None:
         self.hof = HallOfFame(hof_size)
         self.popsize = popsize
@@ -126,8 +126,6 @@
         # instead of single best, could add all individuals in population here, but then the outcome would depend on the order of adding
         self.hof.add(best)
-        self.stats.append(
-            best.rawfitness if self.save_only_best else best)
-        print("%d\t%d\t%g\t%g" % (generation, len(
-            all_individuals), worst.rawfitness, best.rawfitness))
+        self.stats.append(best.rawfitness if self.save_only_best else best)
+        print("%d\t%d\t%g\t%g" % (generation, len(all_individuals), worst.rawfitness, best.rawfitness))
 
     def initialize_evolution(self, initialgenotype):
@@ -149,7 +147,5 @@
             # saved generation has been completed, start with the next one
             self.current_generation += 1
-            print("...Resuming from saved state: population size = %d, hof size = %d, stats size = %d, archive size = %d, generation = %d/%d" % (len(self.population_structures.population), len(self.hof),
-                                                                                                                                                 len(self.stats),  (len(self.population_structures.archive)), self.current_generation, generations))  # self.current_generation (and g) are 0-based, parsed_args.generations is 1-based
-
+            print("...Resuming from saved state: population size = %d, hof size = %d, stats size = %d, archive size = %d, generation = %d/%d" % (len(self.population_structures.population), len(self.hof), len(self.stats), (len(self.population_structures.archive)), self.current_generation, generations))  # self.current_generation (and g) are 0-based, parsed_args.generations is 1-based
         else:
             self.initialize_evolution(initialgenotype)
@@ -192,20 +188,22 @@
     def get_args_for_parser():
         parser = argparse.ArgumentParser()
-        parser.add_argument('-popsize',type= int, default= 50,
+        parser.add_argument('-popsize', type=int, default=50,
                             help="Population size, default: 50.")
-        parser.add_argument('-generations',type= int, default= 5,
+        parser.add_argument('-generations', type=int, default=5,
                                 help="Number of generations, default: 5.")
-        parser.add_argument('-tournament',type= int, default= 5,
+        parser.add_argument('-tournament', type=int, default=5,
                             help="Tournament size, default: 5.")
-        parser.add_argument('-pmut',type= float, default= 0.7,
+        parser.add_argument('-pmut', type=float, default=0.7,
                         help="Probability of mutation, default: 0.7")
-        parser.add_argument('-pxov',type= float, default= 0.2,
+        parser.add_argument('-pxov', type=float, default=0.2,
                         help="Probability of crossover, default: 0.2")
-        parser.add_argument('-hof_size',type= int, default= 10,
+        parser.add_argument('-hof_size', type=int, default=10,
                             help="Number of genotypes in Hall of Fame. Default: 10.")
-        parser.add_argument('-hof_savefile',type= str, required= False,
+        parser.add_argument('-hof_savefile', type=str, required=False,
                                 help= 'If set, Hall of Fame will be saved in Framsticks file format (recommended extension *.gen. This also activates saving state (checpoint} file and auto-resuming from the saved state, if this file exists.')
-        parser.add_argument('-save_only_best',type= bool, default= True, required= False,
+        parser.add_argument('-save_only_best', type=bool, default=True, required=False,
                             help="")
+        parser.add_argument('-fitness_set_negative_to_zero', action='store_true',
+                            help="This flag forces fitness to become max(0,fitness), so it is always made non-negative. Using niching or novelty techniques without this flag (thus allowing negative fitness values) requires verifying/improving fitness diversification formulas to work as intended for both positive and negative fitness values.")
         
         return parser
Index: framspy/evolalg/base/experiment_niching_abc.py
===================================================================
--- framspy/evolalg/base/experiment_niching_abc.py	(revision 1283)
+++ framspy/evolalg/base/experiment_niching_abc.py	(revision 1289)
@@ -24,5 +24,5 @@
     archive_size: int = None
 
-    def __init__(self, fit, normalize, popsize, hof_size, save_only_best=True, knn_niching=5, knn_nslc=10, archive_size=0) -> None:
+    def __init__(self, fit, normalize, popsize, hof_size, save_only_best, knn_niching, knn_nslc, archive_size) -> None:
         ExperimentABC.__init__(self,popsize=popsize, hof_size=hof_size, save_only_best=save_only_best)
         self.fit = fit
@@ -51,5 +51,5 @@
             divide_by = np.sum(dissim_matrix)
         else:
-            raise Exception(f"Wrong normalization method,", self.normalize)
+            raise ValueError("Wrong normalization method: '%s'" % self.normalize)
         if divide_by != 0:
             return dissim_matrix/divide_by
@@ -65,4 +65,7 @@
             dissim_list = np.mean(np.partition(
                 self.normalize_dissim(dissim_matrix), self.knn_niching)[:, :self.knn_niching], axis=1)
+
+        if Individual.fitness_set_negative_to_zero is False and ("niching" in self.fit or "novelty" in self.fit):
+        	raise ValueError("Negative fitness values not tested in combination with niching or novelty. When using these techniques, verify formulas or consider using the flag -fitness_set_negative_to_zero") # once the formulas are verified/improved, the command-line flag and this conditional check can be removed.
 
         if "niching" in self.fit:
@@ -73,6 +76,5 @@
                 i.fitness = d
         else:
-            raise Exception("Wrong fit type: ", self.fit,
-                            f" choose the correct one or implement a new behavior.")
+            raise ValueError("Unsupported fit type: '%s'. Use the correct type or implement a new behavior." % self.fit)
         population_structures.update_archive(dissim_matrix, population_archive)
 
