diff --git a/pulse_lib/segments/conditional_segment.py b/pulse_lib/segments/conditional_segment.py
index 0d988a2022c000c8163e5ad69b4a5bd51d364909..cb991a73ee1565be599b58652b68c4d54d6c2c1b 100644
--- a/pulse_lib/segments/conditional_segment.py
+++ b/pulse_lib/segments/conditional_segment.py
@@ -150,9 +150,9 @@ class conditional_segment:
             for ch in branch.channels:
                 branch[ch].reset_time(loop_obj, False)
 
-    def extend_dim(self, shape=None, ref = False):
+    def extend_dim(self, shape=None):
         for branch in self.branches:
-            branch.extend_dim(shape, ref)
+            branch.extend_dim(shape)
 
     def enter_rendering_mode(self):
         self.reset_time(False)
diff --git a/pulse_lib/segments/segment_container.py b/pulse_lib/segments/segment_container.py
index 250b4dc74cd381a82bb07ba919c9ff04958ef9ec..40eee22a6a933768e5a6d9fb8dd9183f04e64184 100644
--- a/pulse_lib/segments/segment_container.py
+++ b/pulse_lib/segments/segment_container.py
@@ -332,7 +332,7 @@ class segment_container():
         Args:
             extend_only (bool) : will just extend the time in the segment and not reset it if set to true [do not use when composing wavoforms...].
 
-        Allings all segments togeter and sets the input time to 0,
+        Alligns all segments togeter and sets the input time to 0,
         e.g. ,
         chan1 : waveform until 70 ns
         chan2 : waveform until 140ns
@@ -370,12 +370,11 @@ class segment_container():
         '''
         return getattr(self, channel).get_segment(index, sample_rate, ref_channel_states)
 
-    def extend_dim(self, shape=None, ref = False):
+    def extend_dim(self, shape=None):
         '''
         extend the dimensions of the waveform to a given shape.
         Args:
             shape (tuple) : shape of the new waveform
-            ref (bool) : put to True if you want to extend the dimension by using pointers instead of making full copies.
         If referencing is True, a pre-render will already be performed to make sure nothing is rendered double.
         '''
         if shape is None:
@@ -384,15 +383,15 @@ class segment_container():
 
         for i in self.channels:
             if self.render_mode == False:
-                getattr(self, i).data = update_dimension(getattr(self, i).data, shape, ref)
+                getattr(self, i).data = update_dimension(getattr(self, i).data, shape)
 
             if getattr(self, i).type == 'render' and self.render_mode == True:
-                getattr(self, i)._pulse_data_all = update_dimension(getattr(self, i)._pulse_data_all, shape, ref)
+                getattr(self, i)._pulse_data_all = update_dimension(getattr(self, i)._pulse_data_all, shape)
 
         if self.render_mode == False:
-            self._software_markers.data = update_dimension(self._software_markers.data, shape, ref)
+            self._software_markers.data = update_dimension(self._software_markers.data, shape)
         else:
-            self._software_markers._pulse_data_all = update_dimension(self._software_markers.pulse_data_all, shape, ref)
+            self._software_markers._pulse_data_all = update_dimension(self._software_markers.pulse_data_all, shape)
 
     def wait(self, time, channels=None, reset_time=False):
         '''
diff --git a/pulse_lib/segments/utility/data_handling_functions.py b/pulse_lib/segments/utility/data_handling_functions.py
index 145bf56f57f6a698a961227f8235b89037f1ab9a..773bb867e0e6f8a79324827eb51ca1944c7cfe2a 100644
--- a/pulse_lib/segments/utility/data_handling_functions.py
+++ b/pulse_lib/segments/utility/data_handling_functions.py
@@ -44,13 +44,12 @@ def find_common_dimension(dim_1, dim_2):
 
     return tuple(dim_comb[::-1])
 
-def update_dimension(data, new_dimension_info, use_ref = False):
+def update_dimension(data, new_dimension_info):
     '''
     update dimension of the data object to the one specified in new dimension_info
     Args:
         data (np.ndarray[dtype = object]) : numpy object that contains all the segment data of every iteration.
         new_dimension_info (list/np.ndarray) : list of the new dimensions of the array
-        use_ref (bool) : use pointer to copy, or take full copy (False is full copy)
     Returns:
         data (np.ndarray[dtype = object]) : same as input data, but with new_dimension_info.
     '''
@@ -59,30 +58,29 @@ def update_dimension(data, new_dimension_info, use_ref = False):
 
     for i in range(len(new_dimension_info)):
         if data.ndim < i+1:
-            data = _add_dimensions(data, new_dimension_info[-i-1:], use_ref)
+            data = _add_dimensions(data, new_dimension_info[-i-1:])
 
         elif list(data.shape)[-i -1] != new_dimension_info[-i -1]:
             shape = list(data.shape)
             shape[-i-1] = new_dimension_info[-i-1]
-            data = _extend_dimensions(data, shape, use_ref)
+            data = _extend_dimensions(data, shape, -i-1)
 
     return data
 
-def _add_dimensions(data, shape, use_ref):
+def _add_dimensions(data, shape):
     """
     Function that can be used to add and extra dimension of an array object. A seperate function is needed since we want to make a copy and not a reference.
     Note that only one dimension can be extended!
     Args:
         data (np.ndarray[dtype = object]) : numpy object that contains all the segment data of every iteration.
         shape (list/np.ndarray) : list of the new dimensions of the array
-        use_ref (bool) : use pointer to copy, or take full copy (False is full copy)
     """
     new_data =  data_container(shape = shape)
     for i in range(shape[0]):
-        new_data[i] = cpy_numpy_shallow(data, use_ref)
+        new_data[i] = cpy_numpy_shallow(data)
     return new_data
 
-def _extend_dimensions(data, shape, use_ref):
+def _extend_dimensions(data, shape, new_axis):
     '''
     Extends the dimensions of a existing array object. This is useful if one would have first defined sweep axis 2 without defining axis 1.
     In this case axis 1 is implicitly made, only harbouring 1 element.
@@ -91,67 +89,46 @@ def _extend_dimensions(data, shape, use_ref):
     Args:
         data (np.ndarray[dtype = object]) : numpy object that contains all the segment data of every iteration.
         shape (list/np.ndarray) : list of the new dimensions of the array (should have the same lenght as the dimension of the data!)
-        use_ref (bool) : use pointer to copy, or take full copy (False is full copy)
+        axis (int): the axis added in shape
     '''
-    new_data = data_container(shape = shape)
-    for i in range(len(shape)):
-        if data.shape[i] != shape[i]:
-            if i == 0:
-                for j in range(len(new_data)):
-                    new_data[j] = cpy_numpy_shallow(data, use_ref)
-            else:
-                new_data = new_data.swapaxes(i, 0)
-                data = data.swapaxes(i, 0)
+    new_data = data_container(shape=shape)
 
-                for j in range(len(new_data)):
-                    new_data[j] = cpy_numpy_shallow(data, use_ref)
+    if new_axis == 0:
+        for j in range(len(new_data)):
+            new_data[j] = cpy_numpy_shallow(data)
+    else:
+        new_data = new_data.swapaxes(new_axis, 0)
+        data = data.swapaxes(new_axis, 0)
 
-                new_data = new_data.swapaxes(i, 0)
+        for j in range(len(new_data)):
+            new_data[j] = cpy_numpy_shallow(data)
 
+        new_data = new_data.swapaxes(new_axis, 0)
 
     return new_data
 
 
-def cpy_numpy_shallow(data, use_ref):
+def cpy_numpy_shallow(data):
     '''
     Makes a shallow copy of an numpy object array.
 
     Args:
         data : data element
-        use_ref (bool) : use reference to copy
     '''
+    if type(data) != data_container:
+        return copy(data)
 
-    if use_ref == True:
-        if type(data) != data_container:
-            return data
-
-        if data.shape == (1,):
-            return data[0]
+    if data.shape == (1,):
+        return data[0].__copy__()
 
-        shape = data.shape
-        data_flat = data.flatten()
-        new_arr = np.empty(data_flat.shape, dtype=object)
+    shape = data.shape
+    data_flat = data.flatten()
+    new_arr = np.empty(data_flat.shape, dtype=object)
 
-        for i in range(len(new_arr)):
-            new_arr[i] = data_flat[i]
-
-        new_arr = new_arr.reshape(shape)
-
-    else:
-        if type(data) != data_container:
-            return copy(data)
+    for i in range(len(new_arr)):
+        new_arr[i] = copy.copy(data_flat[i])
 
-        if data.shape == (1,):
-            return data[0].__copy__()
-
-        shape = data.shape
-        data_flat = data.flatten()
-        new_arr = np.empty(data_flat.shape, dtype=object)
-
-        for i in range(len(new_arr)):
-            new_arr[i] = copy.copy(data_flat[i])
-
-        new_arr = new_arr.reshape(shape)
+    new_arr = new_arr.reshape(shape)
     return new_arr
 
 
@@ -166,7 +143,7 @@ def _get_loop_info(lp, index):
             setpnt.append(setpnt_single)
 
     info = {
-    'nth_arg': index,
+    'arg_index': index,
     'shape' : lp.shape,
     'len': len(lp),
     'axis': lp.axis,
@@ -193,17 +170,21 @@ def loop_controller(func):
 
         loop_info_args = []
         loop_info_kwargs = []
-        for i in range(1,len(args)):
-            if isinstance(args[i], loop_obj):
-                loop_info_args.append(_get_loop_info(args[i], i))
+        for i,arg in enumerate(args):
+            if isinstance(arg, loop_obj):
+                loop_info_args.append(_get_loop_info(arg, i))
 
-        for key in kwargs.keys():
-            if isinstance(kwargs[key], loop_obj):
-                loop_info_kwargs.append(_get_loop_info(kwargs[key], key))
+        for key,kwarg in kwargs.items():
+            if isinstance(kwarg, loop_obj):
+                loop_info_kwargs.append(_get_loop_info(kwarg, key))
 
+        orig_data = obj.data
         for lp in loop_info_args:
             for i in range(len(lp['axis'])-1,-1,-1):
-                new_dim, axis = get_new_dim_loop(obj.data.shape, lp['axis'][i], lp['shape'][i])
+                data_shape = obj.data.shape
+                lp_axis = lp['axis'][i]
+                lp_length = lp['shape'][i]
+                new_dim, axis = get_new_dim_loop(data_shape, lp_axis, lp_length)
                 lp['axis'][i] = axis
                 obj.data = update_dimension(obj.data, new_dim)
 
@@ -211,7 +192,6 @@ def loop_controller(func):
                     lp['setpnt'][i].axis = axis
                     obj._setpoints += lp['setpnt'][i]
 
-        # todo update : (not used atm, but just to be generaric.)
         for lp in loop_info_kwargs:
             for i in range(len(lp['axis'])-1,-1,-1):
                 new_dim, axis = get_new_dim_loop(obj.data.shape, lp['axis'][i], lp['shape'][i])
@@ -221,11 +201,15 @@ def loop_controller(func):
                 if lp['setpnt'] is not None:
                     lp['setpnt'][i].axis = axis
                     obj._setpoints += lp['setpnt'][i]
-#            new_dim = get_new_dim_loop(obj.data.shape, lp)
-#            obj.data = update_dimension(obj.data, new_dim)
 
-        loop_over_data(func, obj.data, args, loop_info_args, kwargs, loop_info_kwargs)
+        if orig_data is not obj.data:
+            print(f'data {obj.name} change {orig_data.shape}  -> {obj.data.shape}')
 
+        obj_data = obj.data
+        if len(loop_info_args) > 0 or len(loop_info_kwargs) > 0:
+            loop_over_data_lp(func, obj_data, args, loop_info_args, kwargs, loop_info_kwargs)
+        else:
+            loop_over_data(func, obj_data, args, kwargs)
 
     return wrapper
 
@@ -239,7 +223,7 @@ def loop_controller_post_processing(func):
         * extend data format to the right shape (simple python list used).
         * loop over the data and add called function
 
-    loop controller that works on the pulse_data_all object. This acts just before rendering. When rendering is done, all the actions of this looper are done.
+    loop controller that works on the *pulse_data_all* object. This acts just before rendering. When rendering is done, all the actions of this looper are done.
     '''
     @wraps(func)
     def wrapper(*args, **kwargs):
@@ -270,16 +254,19 @@ def loop_controller_post_processing(func):
         for lp in loop_info_kwargs:
             new_dim = get_new_dim_loop(obj.pulse_data_all.shape, lp)
             obj.pulse_data_all = update_dimension(obj.pulse_data_all, new_dim)
-        loop_over_data(func, obj.pulse_data_all, args, loop_info_args, kwargs, loop_info_kwargs)
 
+        obj_data = obj.pulse_data_all
+        if len(loop_info_args) > 0 or len(loop_info_kwargs) > 0:
+            loop_over_data_lp(func, obj_data, args, loop_info_args, kwargs, loop_info_kwargs)
+        else:
+            loop_over_data(func, obj_data, args, kwargs)
 
     return wrapper
 
 
-
-def loop_over_data(func, data, args, args_info, kwargs, kwargs_info):
+def loop_over_data_lp(func, data, args, args_info, kwargs, kwargs_info):
     '''
-    recursive function to apply the
+    Recursive function to apply the func to data with looping args
 
     Args:
         func : function to execute
@@ -288,34 +275,63 @@ def loop_over_data(func, data, args, args_info, kwargs, kwargs_info):
         args_info : argument info is provided (e.g. axis updates)
         kwargs : kwargs provided
         kwarfs_info : same as args_info
-        loop_dimension
-
-
-    Returns:
-        None
     '''
-    shape = list(data.shape)
+    shape = data.shape
     n_dim = len(shape)
 
     # copy the input --> we will fill in the arrays
-    args_cpy = list(copy.copy(args))
-    kwargs_cpy = copy.copy(kwargs)
+    # only copy when there are loops
+    if len(args_info) > 0:
+        # copy to new list
+        args_cpy = list(args)
+    else:
+        args_cpy = args
+    if len(kwargs_info) > 0:
+        kwargs_cpy = kwargs.copy()
+    else:
+        kwargs_cpy = kwargs
 
     for i in range(shape[0]):
         for arg in args_info:
             if n_dim-1 in arg['axis']:
-                args_cpy[arg['nth_arg']] = args[arg['nth_arg']][i]
+                index = arg['arg_index']
+                args_cpy[index] = args[index][i]
         for kwarg in kwargs_info:
             if n_dim-1 in kwarg['axis']:
-                kwargs_cpy[kwarg['nth_arg']] = kwargs[kwarg['nth_arg']][i]
+                index = kwarg['arg_index']
+                kwargs_cpy[index] = kwargs[index][i]
 
         if n_dim == 1:
             # we are at the lowest level of the loop.
-            args_cpy[0].data_tmp = data[i]
+            args[0].data_tmp = data[i]
             data[i] = func(*args_cpy, **kwargs_cpy)
         else:
             # clean up args, kwargs
-            loop_over_data(func, data[i], args_cpy, args_info, kwargs_cpy, kwargs_info)
+            loop_over_data_lp(func, data[i], args_cpy, args_info, kwargs_cpy, kwargs_info)
+
+
+def loop_over_data(func, data, args, kwargs):
+    '''
+    Recursive function to apply func to data
+
+    Args:
+        func : function to execute
+        data : data of the segment
+        args: arugments that are provided
+        kwargs : kwargs provided
+    '''
+    shape = data.shape
+    n_dim = len(shape)
+
+    for i in range(shape[0]):
+
+        if n_dim == 1:
+            # we are at the lowest level of the loop.
+            args[0].data_tmp = data[i]
+            data[i] = func(*args, **kwargs)
+        else:
+            loop_over_data(func, data[i], args, kwargs)
+
 
 def get_new_dim_loop(current_dim, axis, shape):
     '''
diff --git a/pulse_lib/segments/utility/looping.py b/pulse_lib/segments/utility/looping.py
index 5e18bf57a9cd9da20dff721c88c5b4619702434c..34fb1c1d5b4a41da61e6506ee616da4ed7e75de8 100644
--- a/pulse_lib/segments/utility/looping.py
+++ b/pulse_lib/segments/utility/looping.py
@@ -62,7 +62,7 @@ class loop_obj():
                 if len(data.shape) == 1:
                     self.setvals = (self.data, )
                 else:
-                        raise ValueError ('Multidimensional setpoints cannot be inferred from input.')
+                    raise ValueError ('Multidimensional setpoints cannot be inferred from input.')
             else:
                 self.setvals = tuple()
                 if isinstance(setvals,list) or isinstance(setvals, np.ndarray):