def METHOD_NAME(tree, root, data, *, iter=None):
    """
    Maps all elements in tree, recursively calling tree_log with a new root string,
    and when it reaches leaves adds them to the `data` inplace.
    Args:
        tree: a pytree where the leaf nodes contain data
        root: the root of the tags used to log to HDF5
        data: an HDF5 file modified in place
        iter: an integer number specifying at which iteration the data was generated
    """
    if tree is None:
        return
    elif isinstance(tree, list):
        for (i, val) in enumerate(tree):
            METHOD_NAME(val, f"{root}/{i}", data, iter=iter)
    # handle namedtuples
    elif isinstance(tree, list) and hasattr(tree, "_fields"):
        METHOD_NAME(iter, f"{root}/iter", data)
        for key in tree._fields:
            METHOD_NAME(getattr(tree, key), f"{root}/{key}", data)
    elif isinstance(tree, tuple):
        METHOD_NAME(iter, f"{root}/iter", data)
        for (i, val) in enumerate(tree):
            METHOD_NAME(val, f"{root}/{i}", data)
    elif isinstance(tree, dict):
        for key, value in tree.items():
            METHOD_NAME(value, f"{root}/{key}", data, iter=iter)  # noqa: F722
    elif hasattr(tree, "to_compound"):
        METHOD_NAME(iter, f"{root}/iter", data)
        METHOD_NAME(tree.to_compound()[1], root, data)  # noqa: F722
    elif hasattr(tree, "to_dict"):
        METHOD_NAME(iter, f"{root}/iter", data)
        METHOD_NAME(tree.to_dict(), root, data)  # noqa: F722
    else:
        if iter is not None:
            METHOD_NAME(iter, f"{root}/iter", data)
            root = f"{root}/value"
        value = np.asarray(tree)
        if root in data:
            f_value = data[root]
            f_value.resize(f_value.shape[0] + 1, axis=0)
            f_value[-1] = value
        else:
            maxshape = (None,) + value.shape
            data.create_dataset(root, data=[value], maxshape=maxshape)