diff --git a/smooth/optimization/run_optimization.py b/smooth/optimization/run_optimization.py
index 7304666..0a4c89b 100644
--- a/smooth/optimization/run_optimization.py
+++ b/smooth/optimization/run_optimization.py
@@ -455,7 +455,9 @@ def fitness_function(
     # update (copied) oemof model
     for i, av in enumerate(attribute_variation):
         if ignore_zero and individual[i] == 0:
-            del model['components'][av.comp_name]
+            # remove component with zero value from model
+            # use pop instead of del in case component is removed multiple times
+            model['components'].pop(av.comp_name, None)
         else:
             model['components'][av.comp_name][av.comp_attribute] = individual[i]
 

ignore_zero may lead to KeyError
When setting a component's attributes to zero more than once with the GA parameter ignore_zero, the optimization will fail with KeyError. This is caused by trying to remove a component that has been removed before.
diff --git a/tests/test_optimization.py b/tests/test_optimization.py
index 0662854..396362e 100644
--- a/tests/test_optimization.py
+++ b/tests/test_optimization.py
@@ -198,7 +198,8 @@ class TestGA:
     def test_fitness(self):
         idx = 1
         ind = opt.Individual([1])
-        (idx2, ind2) = opt.fitness_function(idx, ind, None, [], None, False)
+        (idx2, ind2) = opt.fitness_function(idx, ind, None, [], None,
+                                            ignore_zero=False, save_results=False)
 
         assert idx == idx2
         for gene_idx, gene in enumerate(ind):
@@ -207,6 +208,24 @@ class TestGA:
         assert ind2.fitness is None
         assert ind2.smooth_result is None
 
+        # test ignore_zero
+        ind = opt.Individual([0])
+        model = {"components": {"foo": {"bar": 0}, "bar": {"foo": 0}}}
+        av = [opt.AttributeVariation(self.av_dict)]
+        opt.fitness_function(idx, ind, model, av, None, ignore_zero=False, save_results=False)
+        assert {"foo", "bar"} == model["components"].keys()
+
+        # ignore_zero: remove foo from model
+        opt.fitness_function(idx, ind, model, av, None, ignore_zero=True, save_results=False)
+        assert {"bar"} == model["components"].keys()
+
+        # ignore_zero twice on same component
+        model = {"components": {"foo": {"bar": 0}, "bar": {"foo": 0}}}
+        ind = opt.Individual([0, 0])
+        av = [opt.AttributeVariation(self.av_dict)]*2
+        opt.fitness_function(idx, ind, model, av, None, ignore_zero=True, save_results=False)
+        assert {"bar"} == model["components"].keys()
+
     def test_optimization(self):
         o = opt.Optimization({
             "population_size": 10,

pip install -e .
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc git clone https://github.com/oemof/oemof-solph.git cd oemof-solph git checkout 585b123e3dc02b191fead4d202ba60c057c473fd pip install . cd ..
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
appdirs==1.4.4
attrs==22.2.0
blinker==1.5
certifi==2021.5.30
cycler==0.11.0
decorator==4.4.2
dill==0.3.4
importlib-metadata==4.8.3
iniconfig==1.1.1
kiwisolver==1.3.1
matplotlib==3.3.4
networkx==2.5.1
nose==1.3.7
numpy==1.17.5
oemof @ file:///smooth/oemof-solph
packaging==21.3
pandas==0.25.3
Pillow==8.4.0
pluggy==1.0.0
ply==3.11
py==1.11.0
Pyomo==5.6.9
pyparsing==3.1.4
pytest==7.0.1
python-dateutil==2.9.0.post0
pytz==2025.2
PyUtilib==5.8.0
scipy==1.5.4
six==1.17.0
-e git+https://github.com/rl-institut/smooth.git@1e77c8860d5401804cf86376bce2b8b9e4afca29#egg=smooth
tomli==1.2.3
typing_extensions==4.1.1
zipp==3.6.0

name: smooth
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - appdirs==1.4.4
      - attrs==22.2.0
      - blinker==1.5
      - cycler==0.11.0
      - decorator==4.4.2
      - dill==0.3.4
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - kiwisolver==1.3.1
      - matplotlib==3.3.4
      - networkx==2.5.1
      - nose==1.3.7
      - numpy==1.17.5
      - oemof==0.3.3.dev0
      - packaging==21.3
      - pandas==0.25.3
      - pillow==8.4.0
      - pluggy==1.0.0
      - ply==3.11
      - py==1.11.0
      - pyomo==5.6.9
      - pyparsing==3.1.4
      - pytest==7.0.1
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyutilib==5.8.0
      - scipy==1.5.4
      - six==1.17.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - zipp==3.6.0
prefix: /opt/conda/envs/smooth

tests/test_optimization.py::TestGA::test_fitness
tests/test_optimization.py::TestAV::test_av tests/test_optimization.py::TestIndividual::test_individual tests/test_optimization.py::TestIndividual::test_domination tests/test_optimization.py::TestSort::test_sort_by_values tests/test_optimization.py::TestSort::test_fnds tests/test_optimization.py::TestSort::test_cdf tests/test_optimization.py::TestGA::test_crossover tests/test_optimization.py::TestGA::test_mutate tests/test_optimization.py::TestGA::test_optimization
smooth/optimization/run_optimization.py
smooth/optimization/run_optimization.py