diff --git a/dynamics.py b/dynamics.py
index 5e011f85f23a842e6cddabbc1cc73a2ef04315ff..e99154204de5b6c0a6f2a01b27ce027800e5a851 100644
--- a/dynamics.py
+++ b/dynamics.py
@@ -677,6 +677,7 @@ def compute_assignment_to_backed(
                 dynamic.step_length_p(source_position) / target_length,
             )
         assignment.add_expression(target_position, expression)
+    assignment.compile()
     return assignment
 
 
@@ -688,10 +689,11 @@ def compute_assignment_from_backed(
     first_target_position = target_dynamic.position_of(dynamic.indices[0])
     for source_position, next_source_index in enumerate(dynamic.indices[1:]):
         next_target_position = target_dynamic.position_of(next_source_index)
-        assignment.add_distribute(
+        assignment.add_distribution(
             first_target_position, next_target_position, source_position
         )
         first_target_position = next_target_position
+    assignment.compile()
     return assignment
 
 
@@ -704,6 +706,7 @@ def compute_assignment_common_reference(
         dynamic.indices[-1] <= target_dynamic.indices[0]
         or target_dynamic.indices[-1] <= dynamic.indices[0]
     ):
+        assignment.compile()
         return assignment
     target_i_start = target_dynamic.indices[0]
     if target_i_start not in dynamic.indices:
@@ -736,6 +739,7 @@ def compute_assignment_common_reference(
                 elif (
                     root_p_start > dynamic.indices[-1]
                 ):  # because root is a RootDynamic, positions and indices are equivalent
+                    assignment.compile()
                     return assignment  # here, we discover that the entire dynamic does not cover one time_step of the target_dynamic
             target_position = target_dynamic.position_of(
                 root_p_start
@@ -753,6 +757,7 @@ def compute_assignment_common_reference(
             if remaining_length == 0:
                 source_position += 1
                 if source_position >= len(dynamic.indices) - 1:
+                    assignment.compile()
                     return assignment
                 remaining_length = dynamic.step_length_p(source_position)
             if remaining_target_length <= remaining_length:
@@ -767,6 +772,7 @@ def compute_assignment_common_reference(
                 remaining_length -= remaining_length
         assignment.add_expression(target_position, expression)
         target_position += 1
+    assignment.compile()
     return assignment
 
 
@@ -783,10 +789,18 @@ class Assignment(abc.ABC):
     ):  # values: type hinting a np-array, type hinting a np-array
         pass
 
-    # # adds the values indexed by source into the target values indexed by target
-    # @abc.abstractmethod
-    # def resample_into(self, values, source_start, source_end, target_values, target_start, target_end):
-    #     pass
+    # adds the values indexed by source into the target values indexed by target
+    @abc.abstractmethod
+    def resample_into(
+        self,
+        values,
+        source_start: int,
+        source_end: int,
+        target_values,
+        target_start: int,
+        target_end: int,
+    ):  # values: type hinting a np-array, target_values: type hinting a np-array
+        pass
 
     # generates expressions representing the resampling
     @abc.abstractmethod
@@ -812,7 +826,24 @@ class AssignmentSame(Assignment):
             raise IndexError("Source values do not cover all target time steps!")
         if source_end < target_end:
             raise IndexError("Source values do not cover all target time steps!")
-        return values[target_start - source_start : target_end - source_start]
+        return values[:, target_start - source_start : target_end - source_start]
+
+    def resample_into(
+        self,
+        values,
+        source_start: int,
+        source_end: int,
+        target_values,
+        target_start: int,
+        target_end: int,
+    ):  # values: type hinting a np-array, target_values: type hinting a np-array
+        if source_start < target_start:
+            raise IndexError("Target values do not cover all source time steps!")
+        if target_end < source_end:
+            raise IndexError("Target values do not cover all source time steps!")
+        target_values[
+            :, source_start - target_start : source_end - target_start
+        ] = values
 
     def resample_variable(
         self, variable, source_start, source_end, target_start, target_end
@@ -841,6 +872,31 @@ class AssignmentToBacked(Assignment):
     ):  # expression: type hinting a np-array of (int, float)
         self.expressions[target_position] = expression
 
+    def compile(self):
+        self.first_complete_expression = np.empty(
+            len(self.indices), dtype=int
+        )  # self.first_complete_expression[source_position] is the index of the first complete expression that the source dynamic covers, if it would start with source_position
+        self.last_complete_expression = np.empty(
+            len(self.indices), dtype=int
+        )  # self.last_complete_expression[source_position] is 1 plus the index of the last complete expression that the source dynamic covers, if it would end with source_position
+        next_position_to_assign_first = 0
+        next_position_to_assign_last = 0
+        for i, expression in enumerate(self.expressions):
+            self.first_complete_expression[
+                next_position_to_assign_first : expression[0][0] + 1
+            ] = i
+            next_position_to_assign_first = expression[0][0] + 1
+            self.last_complete_expression[
+                next_position_to_assign_last : expression[-1][0] + 1
+            ] = i
+            next_position_to_assign_last = expression[-1][0] + 1
+        self.first_complete_expression[next_position_to_assign_first:] = len(
+            self.expressions
+        )
+        self.last_complete_expression[next_position_to_assign_last:] = len(
+            self.expressions
+        )
+
     def resample(
         self,
         values,
@@ -857,16 +913,50 @@ class AssignmentToBacked(Assignment):
             raise IndexError("Source values do not cover all target time steps!")
         if source_i_end < target_i_end:
             raise IndexError("Source values do not cover all target time steps!")
-        target_values = np.empty(target_end - target_start, dtype=values.dtype)
+        target_values = np.empty(
+            (values.shape[0], target_end - target_start), dtype=values.dtype
+        )
         for local_target_position, expression in enumerate(
             self.expressions[target_start:target_end]
         ):
             acc = 0.0
             for source_position, factor in expression:
-                acc += factor * values[source_position - source_start]
-            target_values[local_target_position] = acc
+                acc += factor * values[:, source_position - source_start]
+            target_values[:, local_target_position] = acc
         return target_values
 
+    def resample_into(
+        self,
+        values,
+        source_start: int,
+        source_end: int,
+        target_values,
+        target_start: int,
+        target_end: int,
+    ):  # values: type hinting a np-array, target_values: type hinting a np-array
+        source_i_start = self.indices[source_start]
+        source_i_end = self.indices[source_end]
+        target_i_start = self.target_indices[target_start]
+        target_i_end = self.target_indices[target_end]
+        if source_i_start < target_i_start:
+            raise IndexError("Target values do not cover all source time steps!")
+        if target_i_end < source_i_end:
+            raise IndexError("Target values do not cover all source time steps!")
+        first_complete_expression = self.first_complete_expression[source_start]
+        for local_target_position, expression in enumerate(
+            self.expressions[
+                max(first_complete_expression, target_start) : min(
+                    self.last_complete_expression[source_end], target_end
+                )
+            ]
+        ):
+            acc = 0.0
+            for source_position, factor in expression:
+                acc += factor * values[:, source_position - source_start]
+            target_values[
+                :, local_target_position + first_complete_expression - target_start
+            ] = acc
+
     def resample_variable(
         self, variable, source_start, source_end, target_start, target_end
     ):
@@ -888,8 +978,8 @@ class AssignmentToBacked(Assignment):
         ):
             acc = 0.0
             for source_position, factor in expression:
-                acc += factor * variable[source_position - source_start]
-            target_variable[local_target_position] = acc
+                acc += factor * variable[:, source_position - source_start]
+            target_variable[:, local_target_position] = acc
         return target_variable
 
 
@@ -897,14 +987,29 @@ class AssignmentFromBacked(Assignment):
     def __init__(
         self, indices, target_indices
     ):  # indices: type hinting a np-array of ints, target_indices: type hinting a np-array of ints
-        self.index = indices
+        self.indices = indices
         self.target_indices = target_indices
-        self.indices = np.empty(len(target_indices) - 1, dtype=int)
+        self.distributions = np.empty(len(indices) - 1, dtype=object)
 
-    def add_distribute(
+    def add_distribution(
         self, first_target_position: int, end_target_position: int, source_position: int
     ):
-        self.indices[first_target_position:end_target_position] = source_position
+        self.distributions[source_position] = (
+            first_target_position,
+            end_target_position,
+        )
+
+    def compile(self):
+        self.distribution_positions = np.full(len(self.target_indices), -1, dtype=int)
+        self.source_to_target = np.empty(len(self.indices), dtype=int)
+        for source_position, (first_target_position, end_target_position) in enumerate(
+            self.distributions
+        ):
+            self.distribution_positions[
+                first_target_position:end_target_position
+            ] = source_position
+            self.source_to_target[source_position] = first_target_position
+        self.source_to_target[-1] = self.distributions[-1][1]
 
     def resample(
         self,
@@ -914,15 +1019,47 @@ class AssignmentFromBacked(Assignment):
         target_start: int,
         target_end: int,
     ):  # values: type hinting a np-array, type hinting a np-array
-        source_i_start = self.index[source_start]
-        source_i_end = self.index[source_end]
+        source_i_start = self.indices[source_start]
+        source_i_end = self.indices[source_end]
         target_i_start = self.target_indices[target_start]
         target_i_end = self.target_indices[target_end]
         if target_i_start < source_i_start:
             raise IndexError("Source values do not cover all target time steps!")
         if source_i_end < target_i_end:
             raise IndexError("Source values do not cover all target time steps!")
-        return values[self.indices[target_start:target_end] - source_start]
+        return values[
+            :, self.distribution_positions[target_start:target_end] - source_start
+        ]
+
+    def resample_into(
+        self,
+        values,
+        source_start: int,
+        source_end: int,
+        target_values,
+        target_start: int,
+        target_end: int,
+    ):  # values: type hinting a np-array, target_values: type hinting a np-array
+        source_i_start = self.indices[source_start]
+        source_i_end = self.indices[source_end]
+        target_i_start = self.target_indices[target_start]
+        target_i_end = self.target_indices[target_end]
+        if source_i_start < target_i_start:
+            raise IndexError("Target values do not cover all source time steps!")
+        if target_i_end < source_i_end:
+            raise IndexError("Target values do not cover all source time steps!")
+        target_values[
+            :,
+            self.source_to_target[source_start]
+            - target_start : self.source_to_target[source_end]
+            - target_start,
+        ] = values[
+            :,
+            self.distribution_positions[
+                self.source_to_target[source_start] : self.source_to_target[source_end]
+            ]
+            - source_start,
+        ]
 
     def resample_variable(
         self, variable, source_start, source_end, target_start, target_end
@@ -941,10 +1078,10 @@ class AssignmentFromBacked(Assignment):
             )
         target_variable = np.empty(target_end - target_start, dtype=object)
         for local_target_position, source_position in enumerate(
-            self.indices[target_start:target_end]
+            self.distribution_positions[target_start:target_end]
         ):
-            target_variable[local_target_position] = variable[
-                source_position - source_start
+            target_variable[:, local_target_position] = variable[
+                :, source_position - source_start
             ]
         return target_variable
 
@@ -962,6 +1099,34 @@ class AssignmentCommon(Assignment):
     ):  # expression: type hinting a np-array of (int, float)
         self.expressions[target_position] = expression
 
+    def compile(self):
+        self.first_complete_expression = np.empty(
+            len(self.indices), dtype=int
+        )  # self.first_complete_expression[source_position] is the index of the first complete expression that the source dynamic covers, if it would start with source_position
+        self.last_complete_expression = np.empty(
+            len(self.indices), dtype=int
+        )  # self.last_complete_expression[source_position] is 1 plus the index of the last complete expression that the source dynamic covers, if it would end with source_position
+        next_position_to_assign_first = 0
+        next_position_to_assign_last = 0
+        last_existing_expression = 0
+        for i, expression in enumerate(self.expressions):
+            if expression is not None:
+                self.first_complete_expression[
+                    next_position_to_assign_first : expression[0][0] + 1
+                ] = i
+                next_position_to_assign_first = expression[0][0] + 1
+                self.last_complete_expression[
+                    next_position_to_assign_last : expression[-1][0] + 1
+                ] = i
+                next_position_to_assign_last = expression[-1][0] + 1
+                last_existing_expression = i
+        self.first_complete_expression[next_position_to_assign_first:] = (
+            last_existing_expression + 1
+        )
+        self.last_complete_expression[next_position_to_assign_last:] = (
+            last_existing_expression + 1
+        )
+
     def resample(
         self,
         values,
@@ -978,16 +1143,50 @@ class AssignmentCommon(Assignment):
             raise IndexError("Source values do not cover all target time steps!")
         if source_i_end < target_i_end:
             raise IndexError("Source values do not cover all target time steps!")
-        target_values = np.empty(target_end - target_start, dtype=values.dtype)
+        target_values = np.empty(
+            (values.shape[0], target_end - target_start), dtype=values.dtype
+        )
         for local_target_position, expression in enumerate(
             self.expressions[target_start:target_end]
         ):
             acc = 0.0
             for source_position, factor in expression:
-                acc += factor * values[source_position - source_start]
-            target_values[local_target_position] = acc
+                acc += factor * values[:, source_position - source_start]
+            target_values[:, local_target_position] = acc
         return target_values
 
+    def resample_into(
+        self,
+        values,
+        source_start: int,
+        source_end: int,
+        target_values,
+        target_start: int,
+        target_end: int,
+    ):  # values: type hinting a np-array, target_values: type hinting a np-array
+        source_i_start = self.indices[source_start]
+        source_i_end = self.indices[source_end]
+        target_i_start = self.target_indices[target_start]
+        target_i_end = self.target_indices[target_end]
+        if source_i_start < target_i_start:
+            raise IndexError("Target values do not cover all source time steps!")
+        if target_i_end < source_i_end:
+            raise IndexError("Target values do not cover all source time steps!")
+        first_complete_expression = self.first_complete_expression[source_start]
+        for local_target_position, expression in enumerate(
+            self.expressions[
+                max(first_complete_expression, target_start) : min(
+                    self.last_complete_expression[source_end], target_end
+                )
+            ]
+        ):
+            acc = 0.0
+            for source_position, factor in expression:
+                acc += factor * values[:, source_position - source_start]
+            target_values[
+                :, local_target_position + first_complete_expression - target_start
+            ] = acc
+
     def resample_variable(
         self, variable, source_start, source_end, target_start, target_end
     ):
@@ -1009,8 +1208,8 @@ class AssignmentCommon(Assignment):
         ):
             acc = 0.0
             for source_position, factor in expression:
-                acc += factor * variable[source_position - source_start]
-            target_variable[local_target_position] = acc
+                acc += factor * variable[:, source_position - source_start]
+            target_variable[:, local_target_position] = acc
         return target_variable
 
 
@@ -1179,7 +1378,52 @@ def resample_aggregation_down(
             f"The period dynamic has to be part of the aggregated dynamic!"
         )
     offset = dynamic.offsets(target_dynamic.period_index)
-    return values[offset[0] : offset[1]]
+    return values[:, offset[0] : offset[1]]
+
+
+def resample_into(
+    values, dynamic: Dynamic, target_values, target_dynamic: Dynamic
+):  # values: type hinting a np-array, target_values: type hinting a np-array
+    if dynamic == target_dynamic:
+        target_values[:] = values
+    elif isinstance(dynamic, TreeDynamic) and isinstance(target_dynamic, TreeDynamic):
+        resample_into_tree(values, dynamic, target_values, target_dynamic)
+    elif isinstance(dynamic, PeriodDynamic) and isinstance(
+        target_dynamic, AggregatedDynamic
+    ):
+        resample_aggregation_up(values, dynamic, target_values, target_dynamic)
+    else:
+        raise ValueError(
+            f"Invalid dynamic type combination {type(dynamic)} -> {type(target_dynamic)}!"
+        )
+
+
+def resample_into_tree(
+    values, dynamic: TreeDynamic, target_values, target_dynamic: TreeDynamic
+):  # values: type hinting a np-array, target_values: type hinting a np-array
+    if dynamic.root() != target_dynamic.root():
+        raise ValueError("Both dynamics have to have the same root dynamic!")
+    (
+        assignment,
+        source_start,
+        source_end,
+        target_start,
+        target_end,
+    ) = dynamic.dynamic_tree.get_assignment(dynamic, target_dynamic)
+    assignment.resample_into(
+        values, source_start, source_end, target_values, target_start, target_end
+    )
+
+
+def resample_aggregation_up(
+    values, dynamic: PeriodDynamic, target_values, target_dynamic: AggregatedDynamic
+):  # values: type hinting a np-array, target_values: type hinting a np-array
+    if dynamic.aggregated_dynamic != target_dynamic:
+        raise ValueError(
+            f"The period dynamic has to be part of the aggregated dynamic!"
+        )
+    offset = target_dynamic.offsets(dynamic.period_index)
+    target_values[:, offset[0] : offset[1]] = values
 
 
 def resample_variable(variable, dynamic: Dynamic, target_dynamic: Dynamic):
@@ -1246,7 +1490,10 @@ class Profile:
     def resample(self, dynamic: Dynamic) -> "Profile":
         if dynamic == self.dynamic:
             return self
-        return Profile(resample(self.values, self.dynamic, dynamic), dynamic)
+        return Profile(
+            resample(np.expand_dims(self.values, axis=0), self.dynamic, dynamic)[0],
+            dynamic,
+        )
 
 
 def test_single_resampling(
@@ -1261,23 +1508,30 @@ def test_single_resampling(
     i_end = dynamic.index_of(dynamic.number_of_steps())
     target_i_start = target_dynamic.index_of(0)
     target_i_end = target_dynamic.index_of(target_dynamic.number_of_steps())
-    if target_i_start < i_start or i_end < target_i_end:
-        try:
-            result = resample(values, dynamic, target_dynamic)
-        except Exception as error:
-            if str(error) == "Source values do not cover all target time steps!":
-                f.write("fine # ")
-            else:
-                f.write(str(error) + " # ")
-            return
-        f.write("???? # ")
-        return
-    else:
-        try:
-            result = resample(values, dynamic, target_dynamic)
-        except Exception as error:
+    resample_possible = i_start <= target_i_start and target_i_end <= i_end
+    try:
+        result = resample(np.expand_dims(values, axis=0), dynamic, target_dynamic)[0]
+    except Exception as error:
+        if str(error) == "Source values do not cover all target time steps!":
+            f.write("olap # ")
+        else:
+            f.write(str(error) + " # ")
+    resample_into_possible = target_i_start <= i_start and i_end <= target_i_end
+    try:
+        result_into = np.full(
+            (1, target_dynamic.number_of_steps()), np.nan, dtype=float
+        )
+        resample_into(
+            np.expand_dims(values, axis=0), dynamic, target_dynamic, result_into
+        )
+    except Exception as error:
+        if str(error) == "Target values do not cover all source time steps!":
+            f.write("olap # ")
+        else:
             f.write(str(error) + " # ")
-            return
+    result_into = result_into[0]
+    if not resample_possible and not resample_into_possible:
+        return
     target_values = np.full(target_dynamic.number_of_steps(), np.nan, dtype=float)
     # resample from source to ancestor
     first_ancestor_position = ancestor_dynamic.position_of(dynamic.index_of(0))
@@ -1304,10 +1558,16 @@ def test_single_resampling(
                     * ancestor_values[ancestor_position]
                 )
             target_values[target_position] = acc
-    if all(np.isclose(target_values, result)):
-        f.write("fine # ")
-    else:
-        f.write("math # ")
+    if resample_possible:
+        if all(np.isclose(target_values, result)):
+            f.write("fine # ")
+        else:
+            f.write("math # ")
+    if resample_into_possible:
+        if all(np.isclose(target_values, result_into, equal_nan=True)):
+            f.write("fine # ")
+        else:
+            f.write("math # ")
     ancestor_values[:] = np.nan