diff --git a/apps/tutorials/codegen/HeatEquationKernel.py b/apps/tutorials/codegen/HeatEquationKernel.py
index 8339fdff1cca5859ca71b8e8d0e5c06601c7c1f2..1ce85747a63f7a0dd3146ea11f22030a884a3cbe 100644
--- a/apps/tutorials/codegen/HeatEquationKernel.py
+++ b/apps/tutorials/codegen/HeatEquationKernel.py
@@ -1,6 +1,7 @@
 import sys
 sys.path.append('/local/ca00xebo/repos/walberla')
 import sympy as sp
+import numpy as np
 import pystencils as ps
 from pystencils_walberla import CodeGeneration, generate_sweep
 from src.materials.alloys import Ti6Al4V
@@ -20,15 +21,47 @@ with CodeGeneration() as ctx:
     heat_pde_discretized = discretize(heat_pde)
     heat_pde_discretized = heat_pde_discretized.args[1] + heat_pde_discretized.args[0].simplify()
     Ti6Al4V = Ti6Al4V.create_Ti6Al4V(u.center())
-    # density, density_subexpr = Ti6Al4V.density  # Alternative
     subexp = []
     # Iterate over the dictionary items
+    # {'density': [(density, array([50., 40., 30., 20., 10.])), (density_idx, floor(Temp/100) - 2)]}
     for label, assignment_list in Ti6Al4V.assignments.items():
-        for data_label, data_values in assignment_list:
-            data_symbol = ps.TypedSymbol(data_label, Arr(Fp(64)))  # Define the symbol with appropriate type
-            subexp.append(ps.Assignment(data_symbol, data_values))
-    # thermal_diffusivity_expr = thermal_diffusivity_by_heat_conductivity(Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity)
-    thermal_diffusivity_expr = thermal_diffusivity_by_heat_conductivity(Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity)  # Alternative
+        print('assignment_list: ', assignment_list)
+
+        '''# Convert to a list of SymPy floats
+        values_as_list = [sp.Float(float(v)) for v in assignment_list[0][1]]
+        print('values_as_list: ', values_as_list)
+        print('type(values_as_list): ', type(values_as_list))'''
+
+        '''data_label = assignment_list[0][0]
+        data_values = assignment_list[0][1]'''
+
+        for assignment in assignment_list:
+            '''print('data_label: ', data_label)
+            print('type(data_label): ', type(data_label))
+            print('data_values: ', data_values)
+            print('type(data_values): ', type(data_values))'''
+
+            # values_as_tuples = tuple(sp.Float(float(v)) for v in data_values)
+
+            if isinstance(assignment.rhs, tuple):
+                data_symbol = ps.TypedSymbol(assignment.lhs.name, Arr(Fp(64)))
+                subexp.append(ps.Assignment(data_symbol, assignment.rhs))
+            elif isinstance(assignment.rhs, sp.Expr):
+                data_symbol = ps.TypedSymbol(assignment.lhs.name, dtype='int64')
+                subexp.append(ps.Assignment(data_symbol, assignment.rhs))
+
+        # data_symbol_array = ps.TypedSymbol(assignment_list[0][0].label.name, data_type='list', dtype='float64')
+        # data_symbol_array = ps.TypedSymbol(assignment_list[0][0].name, ps.types.PsArrayType(ps.create_type("float64")))
+        # data_symbol = ps.TypedSymbol(assignment_list[0][0].label.name, Arr(Fp(64)))  #
+
+        # data_symbol_array = sp.IndexedBase(data_symbol_array, shape=len(assignment_list[0][1]))
+
+        # subexp.append(ps.Assignment(data_symbol, values_as_list))  #
+
+        # data_symbol_idx = ps.TypedSymbol(assignment_list[1][0].name, dtype='int64')
+        # subexp.append(ps.Assignment(data_symbol_idx, (assignment_list[1][1])))  # maybe the CastFunc to Int is necessary here
+
+    thermal_diffusivity_expr = thermal_diffusivity_by_heat_conductivity(Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity)
     subexp.append(ps.Assignment(thermal_diffusivity, thermal_diffusivity_expr))
     ac = ps.AssignmentCollection(
         subexpressions=subexp,
@@ -43,4 +76,6 @@ with CodeGeneration() as ctx:
     # ac = ps.simp.simplifications.add_subexpressions_for_field_reads(ac)
     # ac = ps.simp.sympy_cse(ac)
 
+    print(ac)
+
     generate_sweep(ctx, 'HeatEquationKernel', ac, varying_parameters=((data_type, str(thermal_diffusivity)),))
diff --git a/src/materials/alloys/Alloy.py b/src/materials/alloys/Alloy.py
index c5ff7250bb6d7b830f95957845d951a3483cdf00..00c9e681ea9a15b97f1317700c15210ea0d66d5c 100644
--- a/src/materials/alloys/Alloy.py
+++ b/src/materials/alloys/Alloy.py
@@ -1,16 +1,15 @@
 import numpy as np
-from sympy import Expr
-from typing import List, Union, Dict, Tuple, Any
-from dataclasses import dataclass, field, asdict
-from src.materials.elements import Element
-from src.materials.elements import Ti, Al, V
+from dataclasses import dataclass, field
+from src.materials.elements import Element, Ti, Al, V
+from src.materials.elements import interpolate_atomic_number, interpolate_atomic_mass, interpolate_temperature_boil
+from src.materials.typedefs import ValueTypes, AssignmentType, PropertyTypes
 
 
 # Alloy Base Class
 @dataclass
 class Alloy:
-    elements: List[Element]
-    composition: List[float]
+    elements: list[Element]
+    composition: ValueTypes
 
     atomic_number: float = field(init=False)
     atomic_mass: float = field(init=False)
@@ -19,34 +18,33 @@ class Alloy:
     temperature_solidus: float
     temperature_liquidus: float
 
-    latent_heat_of_fusion: Union[float, Expr] = None
-    latent_heat_of_vaporization: Union[float, Expr] = None
-    density: Union[float, Expr] = None
-    thermal_expansion_coefficient: Union[float, Expr] = None
-    heat_capacity: Union[float, Expr] = None
-    heat_conductivity: Union[float, Expr] = None
-    thermal_diffusivity: Union[float, Expr] = None
+    latent_heat_of_fusion: PropertyTypes = None
+    latent_heat_of_vaporization: PropertyTypes = None
+    density: PropertyTypes = None
+    thermal_expansion_coefficient: PropertyTypes = None
+    heat_capacity: PropertyTypes = None
+    heat_conductivity: PropertyTypes = None
+    thermal_diffusivity: PropertyTypes = None
 
-    # assignments: list[tuple, ...] = field(default_factory=list, init=False)
-    assignments: Dict[str, List[Tuple[str, Any]]] = field(default_factory=dict, init=False)
+    assignments: AssignmentType = field(default_factory=dict, init=False)
 
-    def interpolate(self, quantity: str) -> float:
-        comp = np.asarray(self.composition)
-        qnt = np.asarray([element.__getattribute__(quantity) for element in self.elements])
-        return float(np.sum(comp * qnt))
+    def solidification_interval(self) -> [float, float]:
+        return [self.temperature_solidus, self.temperature_liquidus]
 
     def __post_init__(self):
-        self.atomic_number = self.interpolate("atomic_number")
-        self.atomic_mass = self.interpolate("atomic_mass")
-        self.temperature_boil = self.interpolate("temperature_boil")
+        # if sum(self.composition) != 1.:
+        #     raise ValueError("The sum of the composition array has to be 1 got", sum(self.composition))
+        if not np.isclose(sum(self.composition), 1.0, atol=1e-8):
+            raise ValueError("The sum of the composition array must be 1, got", sum(self.composition))
 
-    def solidification_interval(self) -> [float, float]:
-        return [self.temperature_solidus, self.temperature_liquidus]
+        self.atomic_number = interpolate_atomic_number(self.elements, self.composition)
+        self.atomic_mass = interpolate_atomic_mass(self.elements, self.composition)
+        self.temperature_boil = interpolate_temperature_boil(self.elements, self.composition)
 
 
 if __name__ == '__main__':
     Ti64 = Alloy([Ti, Al, V], [0.90, 0.06, 0.04], 1878, 1928)
-    print(0.9*22+0.06*13+0.04*23, Ti64.interpolate("atomic_number"), Ti64.atomic_number)
+    print(0.9 * 22 + 0.06 * 13 + 0.04 * 23, Ti64.atomic_number)
     print(Ti64.heat_conductivity)
     Ti64.heat_conductivity = 34
     print(Ti64.heat_conductivity)
diff --git a/src/materials/alloys/Ti6Al4V.py b/src/materials/alloys/Ti6Al4V.py
index 52a0026ad197f03fc2cab26f42370b639f833fc6..56e2fa0d19ec224a95185a9c04bbe3dd31ad9bdd 100644
--- a/src/materials/alloys/Ti6Al4V.py
+++ b/src/materials/alloys/Ti6Al4V.py
@@ -1,14 +1,13 @@
 import sympy as sp
-from typing import Union
 from src.materials.alloys.Alloy import Alloy
 from src.materials.elements import Ti, Al, V
 from src.materials.constants import Constants
 from src.materials import interpolators
 from src.materials import models
-# from src.materials.property import Property
+from src.materials.typedefs import VariableTypes, AssignmentType
 
 
-def create_Ti6Al4V(T: Union[float, sp.Symbol]) -> Alloy:
+def create_Ti6Al4V(T: VariableTypes) -> Alloy:
     # 90% Ti, 6% Al, 4% V
     Ti6Al4V = Alloy(
         [Ti, Al, V],
@@ -18,41 +17,62 @@ def create_Ti6Al4V(T: Union[float, sp.Symbol]) -> Alloy:
     )
 
     Ti6Al4V.latent_heat_of_fusion = 290000.0  # m²/s²
-    Ti6Al4V.density = 4430.0  # kg/m³     Ref [5]
     Ti6Al4V.thermal_expansion_coefficient = 10e-6  # /K        Ref[6]
 
-    heat_capacity_expr, heat_capacity_assignments = interpolators.interpolate_equidistant(
-        T, 1820, 20, [700, 800, 900, 1000, 1100, 1200], 'heat_capacity')
-    Ti6Al4V.heat_capacity = heat_capacity_expr
+    # ---------- density ----------
 
-    # Merge the returned assignments into the Ti6Al4V assignments dictionary
-    for label, data in heat_capacity_assignments.items():
-        if label in Ti6Al4V.assignments:
-            Ti6Al4V.assignments[label].extend(data)
-        else:
-            Ti6Al4V.assignments[label] = data
-
-    Ti6Al4V.heat_conductivity = interpolators.interpolate_lookup(
-        T, Ti6Al4V.solidification_interval(), [21.58, 33.60])  # W/m-k
+    # Ti6Al4V.density = 4430.0  # kg/m³     Ref [5]
 
     '''Ti6Al4V.density = models.density_by_thermal_expansion(
-        T, Constants.temperature_room, 4430, Ti6Al4V.thermal_expansion_coefficient)
+        T, Constants.temperature_room, 4430, Ti6Al4V.thermal_expansion_coefficient)'''
+
+    # Using interpolate_equidistant for density
+    density_result, sub_expr_density = interpolators.interpolate_equidistant(
+        T, 1878, 8, [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0], 'density')
+    Ti6Al4V.density = density_result
+    Ti6Al4V.assignments.update({"density": sub_expr_density})
+
+    # older code kept for reference (look at interpolate_equidistant for this implementation)
+    '''Ti6Al4V.density = interpolators.interpolate_equidistant(
+        T, 1878, 8, [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0], Ti6Al4V.assignments, 'density')'''
+    # Error: pystencils.backend.kernelcreation.freeze.FreezeError: Don't know how to freeze expression density_idx
+
+    # Using interpolate_lookup for heat conductivity
+    '''Ti6Al4V.density = interpolators.interpolate_lookup(
+        T, Ti6Al4V.solidification_interval(), [4236.3, 4227.])'''
+
+    # Ti6Al4V.density = interpolators.interpolate_lookup(
+    # T, [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0],
+    # [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0])
+
+    # ---------- heat_capacity ----------
+
+    # Ti6Al4V.heat_capacity = 526.
 
-    Ti6Al4V.density = interpolators.interpolate_lookup(
-        T, [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0],
-        [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0])
+    # Using interpolate_equidistant for heat capacity
+    '''heat_capacity_result, sub_expr_heat_capacity = interpolators.interpolate_equidistant(
+        T, 1820, 20, [526, 540, 550, 560, 570, 580], 'heat_capacity')
+    Ti6Al4V.heat_capacity = heat_capacity_result
+    Ti6Al4V.assignments.update({"heat_capacity": sub_expr_heat_capacity})'''
 
-    density_expr, density_assignments = interpolators.interpolate_equidistant(
-        T, 1878.0, 5,
-        [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0], 'density')
-    Ti6Al4V.density = density_expr
+    # Using interpolate_lookup for heat conductivity
+    Ti6Al4V.heat_capacity = interpolators.interpolate_lookup(
+        T, Ti6Al4V.solidification_interval(), [526, 580.0])
 
-    # Merge the returned assignments into the Ti6Al4V assignments dictionary
-    for label, data in density_assignments.items():
-        if label in Ti6Al4V.assignments:
-            Ti6Al4V.assignments[label].extend(data)
-        else:
-            Ti6Al4V.assignments[label] = data'''
+    # ---------- heat_conductivity ----------
+
+    # Ti6Al4V.heat_conductivity = 6.7
+
+    # Using interpolate_equidistant for heat conductivity
+    '''Ti6Al4V.heat_conductivity, sub_expr_heat_conductivity = interpolators.interpolate_equidistant(
+        T, 20, 1, [6.7, 6.5, 6.3, 6.1, 5.9, 5.7], 'heat_conductivity')
+    Ti6Al4V.assignments.update({"heat_conductivity": sub_expr_heat_conductivity})'''
+
+    # Using interpolate_lookup for heat conductivity
+    Ti6Al4V.heat_conductivity = interpolators.interpolate_lookup(
+        T, Ti6Al4V.solidification_interval(), [21.58, 33.60])
+
+    # ---------- thermal_diffusivity ----------
 
     Ti6Al4V.thermal_diffusivity = models.thermal_diffusivity_by_heat_conductivity(
         Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity)
@@ -63,10 +83,45 @@ def create_Ti6Al4V(T: Union[float, sp.Symbol]) -> Alloy:
 if __name__ == '__main__':
     Temp = sp.Symbol('Temp')
     alloy = create_Ti6Al4V(Temp)
-    print('Ti6Al4V')
-    for field in vars(alloy):
-        print(field, "=", alloy.__getattribute__(field))
 
-    print(models.thermal_diffusivity_by_heat_conductivity(500, 5000, 600))
-
-    print(alloy.density.subs(Temp, 1890))
+    print("Testing Ti6Al4V with symbolic temperature:")
+    print('Ti6Al4V Properties:')
+    for field in vars(alloy):
+        print(f"{field} = {alloy.__getattribute__(field)}")
+
+    # Test interpolate_equidistant
+    print("\nTesting interpolate_equidistant:")
+    test_temp = 1850.0  # Example temperature value
+    result, _ = interpolators.interpolate_equidistant(
+        test_temp, 1820, 20.0, [700, 800, 900, 1000, 1100, 1200], 'heat_capacity')
+    print(f"Interpolated heat capacity at T={test_temp} using interpolate_equidistant: {result}")
+
+    _, assignments = interpolators.interpolate_equidistant(
+        Temp, 1820, 20.0, [700, 800, 900, 1000, 1100, 1200], 'heat_capacity')
+    print(f"Assignments: {assignments}")
+
+    result_density, _ = interpolators.interpolate_equidistant(
+        test_temp, 1878, 8, [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0], 'density')
+    print(f"Interpolated density at T={test_temp} using interpolate_equidistant: {result_density}")
+
+    # Test interpolate_lookup
+    print("\nTesting interpolate_lookup:")
+    test_T_array = [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0]
+    test_v_array = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0]
+    result_lookup = interpolators.interpolate_lookup(
+        Temp, test_T_array, test_v_array)
+    print(f"Interpolated value using interpolate_lookup: {result_lookup}")
+
+    # Test thermal diffusivity calculation
+    heat_conductivity = 500  # Example value for testing
+    density = 5000  # Example value for testing
+    heat_capacity = 600  # Example value for testing
+    thermal_diffusivity = models.thermal_diffusivity_by_heat_conductivity(
+        heat_conductivity, density, heat_capacity)
+    print(f"Calculated thermal diffusivity: {thermal_diffusivity}")
+
+    # sp.plot(alloy.heat_conductivity, (Temp, 1800, 2000))
+
+    # sp.plot(alloy.density, (Temp, 1800, 2000))
+
+    # sp.plot(alloy.heat_capacity.subs([(alloy.assignments['heat_capacity'][1][0], alloy.assignments['heat_capacity'][1][1]), (alloy.assignments['heat_capacity'][0][0], alloy.assignments['heat_capacity'][0][1])]), (Temp, 1800, 2000))
diff --git a/src/materials/constants.py b/src/materials/constants.py
index 9c804c57558a058feee8e95d2923c5bad65c8131..a1caa883ca6ccca913d92a1ec261d2ec64d1ed8a 100644
--- a/src/materials/constants.py
+++ b/src/materials/constants.py
@@ -3,6 +3,6 @@ from dataclasses import dataclass
 
 @dataclass
 class Constants:
-    temperature_room =                      298.15          # k
-    N_a =                                   6.022141e23     # /mol
-    u =                                     1.660538e-27    # kg
\ No newline at end of file
+    temperature_room = 298.15  # k
+    N_a = 6.022141e23  # /mol
+    u = 1.660538e-27  # kg
diff --git a/src/materials/elements.py b/src/materials/elements.py
index 049fc1756d98550a2f56042807f88124cc66608b..17cf2e7c19664c374243911df163cf2fdf075c48 100644
--- a/src/materials/elements.py
+++ b/src/materials/elements.py
@@ -1,3 +1,4 @@
+import numpy as np
 from dataclasses import dataclass
 from src.materials.constants import Constants
 
@@ -41,3 +42,24 @@ V = Element(
     latent_heat_of_fusion=21500,
     latent_heat_of_vaporization=444000
 )
+
+
+def interpolate(values, composition) -> float:
+    c = np.asarray(composition)
+    v = np.asarray(values)
+    return float(np.sum(c * v))
+
+
+def interpolate_atomic_number(elements, composition) -> float:
+    values = [element.atomic_number for element in elements]
+    return interpolate(values, composition)
+
+
+def interpolate_temperature_boil(elements, composition) -> float:
+    values = [element.temperature_boil for element in elements]
+    return interpolate(values, composition)
+
+
+def interpolate_atomic_mass(elements, composition) -> float:
+    values = [element.atomic_mass for element in elements]
+    return interpolate(values, composition)
diff --git a/src/materials/interpolators.py b/src/materials/interpolators.py
index 8d57a4bf0bb339952dd62c77dcf910c654b0f5f6..8b945f6df614ffc2831e66dd561d0471d3d1e356 100644
--- a/src/materials/interpolators.py
+++ b/src/materials/interpolators.py
@@ -1,127 +1,232 @@
 import numpy as np
 import sympy as sp
-from typing import Union, List, Tuple, Dict
-# import pystencils as ps
-# from pystencils.types.quick import *
-# from src.materials.property import Property
-from pystencils.sympyextensions import CastFunc
-
-
-def interpolate_equidistant(T: Union[float, sp.Symbol], T_base: float, T_incr: float,
-                            data_array: Union[np.ndarray, List[float]], label: str) \
-        -> Union[float, Tuple[Union[sp.Expr, float], Dict[str, List[Tuple[str, Tuple[float, ...]]]]]]:    # TODO
-    """
-    Interpolates values for equidistant temperature data points.
-
-    :param label:
-    :param T: Temperature value, either symbolic (sp.Expr) or numeric (float).
-    :param T_base: Base temperature value.
-    :param T_incr: Increment between successive temperature data points.
-    :param data_array: Array of data values corresponding to equidistant temperature points.
-    :return: Interpolated value at temperature T.
-    """
+from src.materials.typedefs import ValueTypes, PropertyTypes, VariableTypes, Assignment, AssignmentType
+
+
+# older code kept for reference
+# def interpolate_equidistant(T: VariableTypes, T_base: float, T_incr: float, v_array: ValueTypes, assignments: AssignmentType, label: str) -> PropertyTypes:
+def interpolate_equidistant(T: VariableTypes, T_base: float, T_incr: float, v_array: ValueTypes,
+                            label: str) -> PropertyTypes:
     if isinstance(T, sp.Symbol):
-        # Ensure all data_array elements are compatible with SymPy
-        # data_array = [sp.Float(float(x)) for x in data_array]
-        # data_symbol = sp.IndexedBase('data_symbol', shape=len(data_array))
-        # data_symbol = sp.IndexedBase(ps.TypedSymbol('density_data_symbol', Ptr(Fp(32))), shape=len(data_array))
-        data_array = tuple(sp.Float(float(x)) for x in data_array)  # Alternative
-        # data_symbol = ps.TypedSymbol(label, Arr(Fp(64)))  # Alternative
-        data_base = sp.IndexedBase(label, shape=len(data_array))  # Alternative
-        print(type(data_base))
-        print(type(data_base.label.name))
-        print(type(data_array))
-        # idx = sp.Symbol('idx', integer=True)
-        idx = sp.floor((T - T_base) / T_incr)
-        idx_int = CastFunc(idx, np.int64)
-        print(idx.is_Integer)
-        mod = (T - T_base) - idx * T_incr  # mod replaces (T - T_base) % T_incr
+        data_base = sp.IndexedBase(label, shape=len(v_array))
+        idx = sp.symbols(label + '_idx', cls=sp.Idx)
+
+        pos = (T - T_base) / T_incr
+        pos_int = sp.floor(pos)
+        pos_dec = sp.frac(pos)
+
         result = sp.Piecewise(
-            (data_array[0], T < T_base),
-            (data_array[-1], T >= T_base + (len(data_array) - 1) * T_incr),
-            # (((T_incr - mod) * data_symbol[idx] + (mod * data_symbol[idx + 1])) / T_incr, True))
-            (((T_incr - mod) * data_base[idx_int] + (mod * data_base[idx_int + 1])) / T_incr, True))  # Alternative
-        # return result.subs(data_symbol, sp.Array(data_array))
-        assignments = {label: [(label, data_array)]}
-        return result, assignments  # [result, ps.Assignment(data_symbol, data_array), ps.Assignment(data_symbol, data_array)]  # Alternative resurn a property, 1st arg: result, 2nd: List[tuple]
-    else:
+            (sp.Float(float(v_array[0])), T < T_base),
+            (sp.Float(float(v_array[-1])), T >= T_base + (len(v_array) - 1) * T_incr),
+            ((1 - pos_dec) * data_base[idx] + pos_dec * data_base[idx + 1], True))
+
+        # older code kept for reference
+        '''if label in assignments:
+            raise ValueError("Assigning a label again", label)
+        assignments[label] = (Assignment(data_base, tuple([float(v) for v in v_array])), Assignment(idx, pos_int), )'''
+
+        sub_expressions = (
+            Assignment(data_base, tuple(sp.Float(float(v)) for v in v_array)),
+            Assignment(idx, pos_int),
+        )
+
+        # return result  # older code kept for reference
+        return result, sub_expressions
+    elif isinstance(T, float):
         if T < T_base:
-            return data_array[0]
-        if T > T_base + (len(data_array) - 1) * T_incr:
-            return data_array[-1]
-        idx = int((T - T_base) / T_incr)
-        mod = (T - T_base) - idx * T_incr  # mod replaces (T - T_base) % T_incr
-        return ((T_incr - mod) * data_array[idx] + (mod * data_array[idx + 1])) / T_incr
-
-
-def interpolate_lookup(T: Union[float, sp.Symbol], base_temperature: Union[np.ndarray, List[float]],
-                       base_values: Union[np.ndarray, List[float]]) -> Union[float, sp.Expr]:  # TODO
-    """
-    Interpolates properties based on temperature for both symbolic and numeric cases.
-
-    :param T: Temperature value, either symbolic or numeric.
-    :param base_temperature: List or array of base temperatures.
-    :param base_values: List or array of property values corresponding to base temperatures.
-    """
-    # Ensure that base_temperature and base_values are numpy arrays or lists of floats
-    if isinstance(base_temperature, (np.ndarray, list)):
-        base_temperature = np.array(base_temperature, dtype=float)
-    if isinstance(base_values, (np.ndarray, list)):
-        base_values = np.array(base_values, dtype=float)
-
-    # Check if base_temperature and base_values have the same length
-    if len(base_temperature) != len(base_values):
-        raise ValueError("base_temperature and base_values must have the same length")
-    # assert len(base_temperature) == len(base_values), "base_temperature and base_values must have the same length"
+            return v_array[0], ()
+
+        pos = (T - T_base) / T_incr
+        pos_int = int(pos)
+        pos_dec = np.modf(pos)[0]
+
+        if pos_int + 1 >= len(v_array):
+            return v_array[-1], ()
+
+        value = (1 - pos_dec) * v_array[pos_int] + pos_dec * v_array[pos_int + 1]
+        return value, ()
+    else:
+        raise ValueError(f"Unsupported type for T: {type(T)}")
+
+
+def interpolate_lookup(T: VariableTypes, T_array: ValueTypes, v_array: ValueTypes) -> PropertyTypes:
+    if len(T_array) != len(v_array):  # Check if T_array and v_array have the same length
+        raise ValueError("T_array and v_array must have the same length")
+    # assert len(T_array) == len(v_array), "T_array and v_array must have the same length"
 
     if isinstance(T, sp.Symbol):  # Symbolic expression
-        base_temperature = [sp.Float(float(t)) for t in base_temperature]
-        base_values = [sp.Float(float(val)) for val in base_values]
+        T_array = tuple([sp.Float(float(t)) for t in T_array])  # is it better to have a list or tuple here?
+        print(T_array)
+        v_array = tuple([sp.Float(float(v)) for v in v_array])
+        print(v_array)
+        # T_array = np.asarray(T_array, dtype=sp.Float)
+        # v_array = np.asarray(v_array, dtype=sp.Float)
+
         conditions = [
-            (base_values[0], T < base_temperature[0]),
-            (base_values[-1], T >= base_temperature[-1])]
-        for i in range(len(base_temperature) - 1):
-            interp_expr = (base_values[i] +
-                           (base_values[i + 1] - base_values[i]) / (base_temperature[i + 1] - base_temperature[i]) *
-                           (T - base_temperature[i]))
-            if i + 1 == len(base_temperature) - 1:
-                conditions.append((interp_expr, sp.And(T >= base_temperature[i], T < base_temperature[i + 1])))
-            else:
-                conditions.append((interp_expr, True))
-        # return sp.Piecewise(*conditions)
+            (v_array[0], T < T_array[0]),
+            (v_array[-1], T >= T_array[-1])]
+        for i in range(len(T_array) - 1):
+            interp_expr = (
+                        v_array[i] + (v_array[i + 1] - v_array[i]) / (T_array[i + 1] - T_array[i]) * (T - T_array[i]))
+            conditions.append(
+                (interp_expr, sp.And(T >= T_array[i], T < T_array[i + 1]) if i + 1 < len(T_array) - 1 else True))
         return sp.Piecewise(*conditions)
-    else:  # Numeric expression
-        try:
-            T = float(T)  # Ensure T is a float for numeric case
-        except (TypeError, ValueError) as e:
-            raise ValueError(f"Invalid numeric input for T: {T}") from e
-
-        return np.interp(T, base_temperature, base_values)
+    elif isinstance(T, float):  # Numeric expression
+        return np.interp(T, T_array, v_array)
+    raise ValueError(f"Invalid input for T: Union[float, sp.Symbol] got", type(T))
 
 
+'''
 if __name__ == '__main__':
     # Example usage:
     Temp = sp.Symbol('Temp')
     density_temp_array1 = np.array([200.0, 300.0, 400.0, 500.0, 600.0])
-    density_data_array1 = np.array([50.0, 40.0, 30.0, 20.0, 10.0])
+    density_v_array1 = np.array([50.0, 40.0, 30.0, 20.0, 10.0])
     density_temp_array2 = [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0]
-    density_data_array2 = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0]
+    density_v_array2 = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0]
+
+    assignments = dict()
 
     # Symbolic interpolation
-    symbolic_result = interpolate_lookup(Temp, density_temp_array2, density_data_array2)
+    symbolic_result = interpolate_lookup(Temp, density_temp_array2, density_v_array2)
     print("Symbolic interpolation result with interpolate_lookup:", symbolic_result)
 
     # Numeric interpolation
-    numeric_result = interpolate_lookup(450.0, density_temp_array2, density_data_array2)
+    numeric_result = interpolate_lookup(1900.2, density_temp_array2, density_v_array2)
     print("Numeric interpolation result with interpolate_lookup:", numeric_result)
 
+    # Handle error case for invalid type
+    try:
+        error_result = interpolate_lookup("what's up", density_temp_array2, density_v_array2)
+    except ValueError as e:
+        print("Error:", e)
+
     T_base = 200
     T_incr = 100
 
     # Symbolic interpolation
-    symbolic_result = interpolate_equidistant(Temp, T_base, T_incr, density_data_array2, 'density')
+    symbolic_result, ass1 = interpolate_equidistant(Temp, T_base, T_incr, density_v_array1, 'density')
     print("Symbolic interpolation result with interpolate_equidistant:", symbolic_result)
+    print(ass1)
 
     # Numeric interpolation
-    numeric_result = interpolate_equidistant(450.0, T_base, T_incr, density_data_array2, 'density')
+    numeric_result = interpolate_equidistant(500.0, T_base, T_incr, density_v_array1, 'density')
     print("Numeric interpolation result with interpolate_equidistant:", numeric_result)
+
+    # Ensure proper access to elements in the assignments dictionary
+    for label, assignment_list in assignments.items():
+
+        # Substitute idx and base values into the expression
+        evaluated_result = symbolic_result.subs([
+            (assignments['density'][1][0], assignments['density'][1][1]),  # idx substitution
+            (Temp, 450.0),  # Temperature substitution
+            (assignments['density'][0][0], assignments['density'][0][1])
+        ])
+        print('evaluated_result: ', evaluated_result)
+
+        # Convert NumPy array to standard Python floats before substitution
+        indexed_data = [sp.Float(float(v)) for v in assignments['density'][0][1]]  # Convert to SymPy floats
+        print(indexed_data)
+        indexed_base = assignments['density'][0][0]  # The IndexedBase symbol
+        print(indexed_base)
+
+        # map the IndexedBase to the data array for evaluation
+        for i, value in enumerate(indexed_data):
+            evaluated_result = evaluated_result.subs(indexed_base[i], value)
+
+        print(evaluated_result)
+        print(evaluated_result.evalf())
+'''
+
+if __name__ == '__main__':
+    Temp = sp.Symbol('Temp')
+    density_temp_array1 = np.array([200.0, 300.0, 400.0, 500.0, 600.0])
+    density_v_array1 = np.array([50.0, 40.0, 30.0, 20.0, 10.0])
+    density_temp_array2 = [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0]
+    density_v_array2 = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0]
+
+    T_base = 200
+    T_incr = 100
+
+    # Example usage of interpolate_lookup
+    print("\nInterpolate Lookup Tests:")
+
+    # Symbolic interpolation with arrays
+    symbolic_result = interpolate_lookup(Temp, density_temp_array1, density_v_array1)
+    print("Symbolic interpolation result with interpolate_lookup (arrays):", symbolic_result)
+
+    # Symbolic interpolation with lists
+    symbolic_result_list = interpolate_lookup(Temp, density_temp_array2, density_v_array2)
+    print("Symbolic interpolation result with interpolate_lookup (lists):", symbolic_result_list)
+
+    # Numeric interpolation with arrays
+    numeric_result = interpolate_lookup(1900.2, density_temp_array2, density_v_array2)
+    print("Numeric interpolation result with interpolate_lookup (arrays):", numeric_result)
+
+    # Numeric interpolation with lists
+    numeric_result_list = interpolate_lookup(1900.2, [200.0, 300.0, 400.0, 500.0, 600.0],
+                                             [50.0, 40.0, 30.0, 20.0, 10.0])
+    print("Numeric interpolation result with interpolate_lookup (lists):", numeric_result_list)
+
+    # Error handling test for invalid T type
+    try:
+        error_result = interpolate_lookup("what's up", density_temp_array2, density_v_array2)
+    except ValueError as e:
+        print("Error:", e)
+
+    # Example usage of interpolate_equidistant
+    print("\nInterpolate Equidistant Tests:")
+
+    # Symbolic interpolation with numpy arrays
+    symbolic_result_eq, ass1 = interpolate_equidistant(Temp, T_base, T_incr, density_v_array1, 'density')
+    print("Symbolic interpolation result with interpolate_equidistant (numpy arrays):", symbolic_result_eq)
+    print("Assignments:", ass1)
+
+    # Symbolic interpolation with lists
+    symbolic_result_eq_list, ass2 = interpolate_equidistant(Temp, T_base, T_incr, density_v_array2, 'density')
+    print("Symbolic interpolation result with interpolate_equidistant (lists):", symbolic_result_eq_list)
+    print("Assignments:", ass2)
+
+    # Numeric interpolation with numpy arrays
+    numeric_result_eq, _ = interpolate_equidistant(1900.2, T_base, T_incr, density_v_array1, 'density')
+    print("Numeric interpolation result with interpolate_equidistant (numpy arrays):", numeric_result_eq)
+
+    # Numeric interpolation with lists
+    numeric_result_eq_list, _ = interpolate_equidistant(1900.2, T_base, T_incr, density_v_array2, 'density')
+    print("Numeric interpolation result with interpolate_equidistant (lists):", numeric_result_eq_list)
+
+    # Error handling test for invalid T type in interpolate_equidistant
+    try:
+        error_result_eq = interpolate_equidistant("invalid", T_base, T_incr, density_v_array2, 'density')
+    except ValueError as e:
+        print("Error:", e)
+
+    print("\nConsistency Test between interpolate_lookup and interpolate_equidistant:")
+
+    # Consistency check for a range of temperatures
+    test_temps = [150.0, 200.0, 350.0, 450.0, 550.0, 650.0]
+    for T in test_temps:
+        # Numeric results from interpolate_lookup
+        lookup_result = interpolate_lookup(T, density_temp_array1, density_v_array1)
+
+        # Numeric results from interpolate_equidistant
+        equidistant_result, _ = interpolate_equidistant(T, T_base, T_incr, density_v_array1, 'density')
+
+        # Print and assert for consistency
+        print(f"Temperature {T}:")
+        print(f"interpolate_lookup result: {lookup_result}")
+        print(f"interpolate_equidistant result: {equidistant_result}")
+
+        # Allow a small tolerance for floating-point comparison
+        assert np.isclose(lookup_result, equidistant_result), f"Inconsistent results for T = {T}"
+
+    # Consistency check for symbolic interpolation (equivalent results comparison)
+    symbolic_lookup_result = interpolate_lookup(Temp, density_temp_array1, density_v_array1)
+    symbolic_equidistant_result, assignments = interpolate_equidistant(Temp, T_base, T_incr, density_v_array1,
+                                                                       'density')
+
+    # Print symbolic results
+    print("\nSymbolic interpolation results for consistency check:")
+    print(f"interpolate_lookup (symbolic): {symbolic_lookup_result}")
+    print(f"interpolate_equidistant (symbolic): {symbolic_equidistant_result}")
+    print(f"interpolate_equidistant (symbolic): {assignments}")
diff --git a/src/materials/models.py b/src/materials/models.py
index a4a7372eae51d65e9d8454623148c032d962f480..fb6908013a5101ecda23a93cb93fb69cad1b288a 100644
--- a/src/materials/models.py
+++ b/src/materials/models.py
@@ -1,13 +1,13 @@
-from sympy import Expr, Symbol, simplify
-from typing import Union
+import sympy as sp
+from src.materials.typedefs import PropertyTypes, VariableTypes
 
 
 def density_by_thermal_expansion(
-        T: Union[float, Symbol],
+        T: VariableTypes,
         base_temperature: float,
         base_density: float,
-        thermal_expansion_coefficient: Union[float, Expr]) \
-        -> Union[float, Expr]:
+        thermal_expansion_coefficient: PropertyTypes) \
+        -> PropertyTypes:
     """
     Calculate density based on thermal expansion: rho_0 / (1 + tec * (T - T_0))
 
@@ -20,10 +20,10 @@ def density_by_thermal_expansion(
 
 
 def thermal_diffusivity_by_heat_conductivity(
-        heat_conductivity: Union[float, Expr],
-        density: Union[float, Expr],
-        heat_capacity: Union[float, Expr]) \
-        -> Union[float, Expr]:
+        heat_conductivity: PropertyTypes,
+        density: PropertyTypes,
+        heat_capacity: PropertyTypes) \
+        -> PropertyTypes:
     """
     Calculate thermal diffusivity: k(T) / (rho(T) * c_p(T))
 
@@ -32,6 +32,6 @@ def thermal_diffusivity_by_heat_conductivity(
     :param heat_capacity: Specific heat capacity.
     """
     result = heat_conductivity / (density * heat_capacity)
-    if isinstance(heat_conductivity, Expr) or isinstance(density, Expr) or isinstance(heat_capacity, Expr):
-        result = simplify(result)
+    if isinstance(heat_conductivity, sp.Expr) or isinstance(density, sp.Expr) or isinstance(heat_capacity, sp.Expr):
+        result = sp.simplify(result)
     return result
diff --git a/src/materials/property.py b/src/materials/property.py
deleted file mode 100644
index 7a61e3e21e7ed630642153fc77662c631cce3e05..0000000000000000000000000000000000000000
--- a/src/materials/property.py
+++ /dev/null
@@ -1,8 +0,0 @@
-"""from sympy import Expr
-from dataclasses import dataclass
-
-
-@dataclass
-class Property:
-    expression: Expr | float
-    assignments: tuple[tuple, ...] = tuple"""
diff --git a/src/materials/typedefs.py b/src/materials/typedefs.py
new file mode 100644
index 0000000000000000000000000000000000000000..d56c6d1e7bb6db9b4f1ee95985b7e74018cae474
--- /dev/null
+++ b/src/materials/typedefs.py
@@ -0,0 +1,18 @@
+import numpy as np
+import sympy as sp
+from dataclasses import dataclass
+
+
+@dataclass
+class Assignment:
+    lhs: sp.Symbol
+    rhs: tuple | sp.Expr
+
+
+ValueTypes = np.ndarray | list[float]
+
+PropertyTypes = float | sp.Expr
+
+VariableTypes = float | sp.Symbol
+
+AssignmentType = dict[str, tuple[Assignment, ...]]