diff --git a/vermouth/processors/average_beads.py b/vermouth/processors/average_beads.py
index b126dd7..8c57f2d 100644
--- a/vermouth/processors/average_beads.py
+++ b/vermouth/processors/average_beads.py
@@ -77,7 +77,7 @@ def do_average_bead(molecule, ignore_missing_graphs=False, weight=None):
 
     for node in molecule.nodes.values():
         if 'graph' in node:
-            positions = np.stack([
+            positions = np.array([
                 subnode['position']
                 for subnode in node['graph'].nodes().values()
                 if subnode.get('position') is not None
@@ -87,7 +87,14 @@ def do_average_bead(molecule, ignore_missing_graphs=False, weight=None):
                 for subnode_key, subnode in node['graph'].nodes.items()
                 if subnode.get('position') is not None
             ])
-            node['position'] = np.average(positions, axis=0, weights=weights)
+            try:
+                ndim = positions.shape[1]
+            except IndexError:
+                ndim = 3
+            if abs(sum(weights)) < 1e-7:
+                node['position'] = np.array([np.nan]*ndim, dtype=float)
+            else:
+                node['position'] = np.average(positions, axis=0, weights=weights)
 
     return molecule
 

DoAverageBead breaks if a node has no constructing atoms
In case e.g. an amino acid sidechain is completely missing there are no atoms constructing the SC1 bead (in Martini). `do_average_bead` does not like this, since `np.stack([])` raises an error.

The fix should be a fairly straightforward if/else statement that sets the position to [nan, nan, nan] if there are no constructing atoms.
Related to #17 

Current work-around for users: make sure there is at least 1 atom per bead present in the input.

Found with help from Sebastian.
diff --git a/vermouth/tests/test_average_beads.py b/vermouth/tests/test_average_beads.py
index 4720fea..07fdc12 100644
--- a/vermouth/tests/test_average_beads.py
+++ b/vermouth/tests/test_average_beads.py
@@ -59,6 +59,30 @@ def mol_with_subgraph():
         "target False": np.array([2.6, 3.6, 4.6]),
     })
 
+    subgraph = nx.Graph()
+    mol.add_node(2, **{
+        "graph": subgraph,
+        "mapping_weights": {},
+        "target mass": np.array([np.nan, np.nan, np.nan]),
+        "target not mass": np.array([np.nan, np.nan, np.nan]),
+        "target None": np.array([np.nan, np.nan, np.nan]),
+        "target False": np.array([np.nan, np.nan, np.nan]),
+    })
+
+    subgraph = nx.Graph()
+    subgraph.add_nodes_from((
+        (0, {'mass': 1.2, 'not mass': 2.2, 'position': np.array([2, 3, 4], dtype=float),}),
+        (1, {'mass': 1.3, 'not mass': 2.3, 'position': np.array([3, 4, 5], dtype=float),}),
+    ))
+    mol.add_node(3, **{
+        "graph": subgraph,
+        "mapping_weights": {0: 0, 1: 0},
+        "target mass": np.array([np.nan, np.nan, np.nan]),
+        "target not mass": np.array([np.nan, np.nan, np.nan]),
+        "target None": np.array([np.nan, np.nan, np.nan]),
+        "target False": np.array([np.nan, np.nan, np.nan]),
+    })
+
     return mol
 
 @pytest.fixture(params=(None, 'mass', 'not mass'))
@@ -89,7 +113,7 @@ def test_do_average_bead(mol_with_subgraph, weight):
     target_key = 'target {}'.format(weight)
     target_positions = np.stack([node[target_key] for node in mol_with_subgraph.nodes.values()])
     positions = np.stack([node['position'] for node in mol_with_subgraph.nodes.values()])
-    assert np.allclose(positions, target_positions)
+    assert np.allclose(positions, target_positions, equal_nan=True)
 
 
 @pytest.mark.parametrize('weight', ('mass', 'not mass'))
@@ -120,7 +144,7 @@ def test_processor_variable(mol_with_variable):
     target_key = 'target {}'.format(weight)
     target_positions = np.stack([node[target_key] for node in mol_with_variable.nodes.values()])
     positions = np.stack([node['position'] for node in mol_with_variable.nodes.values()])
-    assert np.allclose(positions, target_positions)
+    assert np.allclose(positions, target_positions, equal_nan=True)
 
 
 @pytest.mark.parametrize('weight', (False, 'mass', 'not mass'))
@@ -130,4 +154,4 @@ def test_processor_weight(mol_with_variable, weight):
     target_key = 'target {}'.format(weight)
     target_positions = np.stack([node[target_key] for node in mol_with_variable.nodes.values()])
     positions = np.stack([node['position'] for node in mol_with_variable.nodes.values()])
-    assert np.allclose(positions, target_positions)
+    assert np.allclose(positions, target_positions, equal_nan=True)

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest coverage pytest-cov pylint hypothesis hypothesis-networkx codecov
apt-get update apt-get install -y gcc
3.9
requirements-docs.txt requirements-tests.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
astroid==3.3.9
attrs==25.3.0
babel==2.17.0
certifi==2025.1.31
charset-normalizer==3.4.1
codecov==2.1.13
coverage==7.8.0
dill==0.3.9
docutils==0.21.2
exceptiongroup==1.2.2
hypothesis==6.130.5
hypothesis-networkx==0.3.0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
isort==6.0.1
Jinja2==3.1.6
MarkupSafe==3.0.2
mccabe==0.7.0
networkx==2.8.8
numpy==2.0.2
packaging==24.2
pbr==6.1.1
platformdirs==4.3.7
pluggy==1.5.0
Pygments==2.19.1
pylint==3.3.6
pytest==8.3.5
pytest-cov==6.0.0
requests==2.32.3
scipy==1.13.1
snowballstemmer==2.2.0
sortedcontainers==2.4.0
Sphinx==7.4.7
sphinxcontrib-apidoc==0.5.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.2.1
tomlkit==0.13.2
typing_extensions==4.13.0
urllib3==2.3.0
-e git+https://github.com/marrink-lab/vermouth-martinize.git@ca5856e938333dbd85aeb88f25316ba54f1fd84a#egg=vermouth
zipp==3.21.0

name: vermouth-martinize
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
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - 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=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - astroid==3.3.9
      - attrs==25.3.0
      - babel==2.17.0
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - codecov==2.1.13
      - coverage==7.8.0
      - dill==0.3.9
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - hypothesis==6.130.5
      - hypothesis-networkx==0.3.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - isort==6.0.1
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - networkx==2.8.8
      - numpy==2.0.2
      - packaging==24.2
      - pbr==6.1.1
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pygments==2.19.1
      - pylint==3.3.6
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - requests==2.32.3
      - scipy==1.13.1
      - snowballstemmer==2.2.0
      - sortedcontainers==2.4.0
      - sphinx==7.4.7
      - sphinxcontrib-apidoc==0.5.0
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - tomlkit==0.13.2
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - vermouth==0.1.1.dev2
      - zipp==3.21.0
prefix: /opt/conda/envs/vermouth-martinize

vermouth/tests/test_average_beads.py::test_do_average_bead[None] vermouth/tests/test_average_beads.py::test_do_average_bead[mass] vermouth/tests/test_average_beads.py::test_do_average_bead[not vermouth/tests/test_average_beads.py::test_processor_variable[None] vermouth/tests/test_average_beads.py::test_processor_variable[mass] vermouth/tests/test_average_beads.py::test_processor_variable[not vermouth/tests/test_average_beads.py::test_processor_weight[None-False] vermouth/tests/test_average_beads.py::test_processor_weight[None-mass] vermouth/tests/test_average_beads.py::test_processor_weight[None-not vermouth/tests/test_average_beads.py::test_processor_weight[mass-False] vermouth/tests/test_average_beads.py::test_processor_weight[mass-mass] vermouth/tests/test_average_beads.py::test_processor_weight[mass-not vermouth/tests/test_average_beads.py::test_processor_weight[not
vermouth/tests/test_average_beads.py::test_shoot_weight[mass] vermouth/tests/test_average_beads.py::test_shoot_weight[not vermouth/tests/test_average_beads.py::test_shoot_graph
vermouth/processors/average_beads.py
vermouth/processors/average_beads.py