From 38e10447e1d94635250bd3dd1165fdf08a295079 Mon Sep 17 00:00:00 2001
From: Rahil Doshi <rahil.doshi@fau.de>
Date: Sun, 2 Mar 2025 01:21:04 +0100
Subject: [PATCH] Move all test files in the tests directory

---
 src/pymatlib/core/cpp/CMakeLists.txt          |  22 +-
 .../core/test_interpolate_functs_perf.py      | 237 ------------------
 tests/cpp/CMakeLists.txt                      |  41 +++
 .../core => tests}/cpp/TestArrayContainer.py  |   0
 .../core => tests}/cpp/test_interpolation.cpp |   0
 tests/legacy/__init__.py                      |   0
 tests/legacy/test_interpolate_functs_perf.py  |  17 ++
 tests/python/__init__.py                      |   0
 tests/{ => python}/test_alloy.py              |   0
 .../{ => python}/test_assignment_converter.py |   0
 tests/{ => python}/test_data_handler.py       |   0
 .../python}/test_interpolation.py             |   0
 tests/{ => python}/test_interpolators.py      |   0
 tests/{ => python}/test_models.py             |   0
 tests/{ => python}/test_typedefs.py           |   0
 .../python}/test_yaml_config.py               |   6 +-
 16 files changed, 70 insertions(+), 253 deletions(-)
 delete mode 100644 src/pymatlib/core/test_interpolate_functs_perf.py
 create mode 100644 tests/cpp/CMakeLists.txt
 rename {src/pymatlib/core => tests}/cpp/TestArrayContainer.py (100%)
 rename {src/pymatlib/core => tests}/cpp/test_interpolation.cpp (100%)
 create mode 100644 tests/legacy/__init__.py
 create mode 100644 tests/python/__init__.py
 rename tests/{ => python}/test_alloy.py (100%)
 rename tests/{ => python}/test_assignment_converter.py (100%)
 rename tests/{ => python}/test_data_handler.py (100%)
 rename {src/pymatlib/core/cpp => tests/python}/test_interpolation.py (100%)
 rename tests/{ => python}/test_interpolators.py (100%)
 rename tests/{ => python}/test_models.py (100%)
 rename tests/{ => python}/test_typedefs.py (100%)
 rename {src/pymatlib/data/alloys/SS316L => tests/python}/test_yaml_config.py (89%)

diff --git a/src/pymatlib/core/cpp/CMakeLists.txt b/src/pymatlib/core/cpp/CMakeLists.txt
index 26261a1..b50fa6a 100644
--- a/src/pymatlib/core/cpp/CMakeLists.txt
+++ b/src/pymatlib/core/cpp/CMakeLists.txt
@@ -34,18 +34,10 @@ target_link_libraries(fast_interpolation PRIVATE
         Python::NumPy
 )
 
-# Add C++ test executable
-add_executable(fast_interpolation_test_cpp test_interpolation.cpp)
-target_compile_features(fast_interpolation_test_cpp PRIVATE cxx_std_11)
-target_compile_options(fast_interpolation_test_cpp PRIVATE -O3)
-target_link_libraries(fast_interpolation_test_cpp PRIVATE
-        interpolation_template
-)
-
-# Add custom target for running Python tests
-add_custom_target(fast_interpolation_test_py
-        COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_interpolation.py
-        DEPENDS fast_interpolation
-        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-        COMMENT "Running Python tests"
-)
+# Remove or update this if test_interpolation.py has been moved
+# add_custom_target(fast_interpolation_test_py
+#         COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_interpolation.py
+#         DEPENDS fast_interpolation
+#         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+#         COMMENT "Running Python tests"
+# )
diff --git a/src/pymatlib/core/test_interpolate_functs_perf.py b/src/pymatlib/core/test_interpolate_functs_perf.py
deleted file mode 100644
index 7aa39d4..0000000
--- a/src/pymatlib/core/test_interpolate_functs_perf.py
+++ /dev/null
@@ -1,237 +0,0 @@
-import time
-import numpy as np
-import sympy as sp
-from pathlib import Path
-from typing import Union
-from pymatlib.core.alloy import Alloy
-from pymatlib.data.element_data import Fe, Cr, Ni, Mo, Mn
-from pymatlib.core.models import thermal_diffusivity_by_heat_conductivity, density_by_thermal_expansion, energy_density
-from pymatlib.core.data_handler import read_data, celsius_to_kelvin, thousand_times, check_equidistant, check_strictly_increasing, plot_arrays
-from pymatlib.core.interpolators import (interpolate_property, temperature_from_energy_density,
-                                         E_eq_from_E_neq, create_idx_mapping, prepare_interpolation_arrays)
-#from pymatlib.core.interpolators import interpolate_binary_search, interpolate_double_lookup
-from pymatlib.core.cpp.fast_interpolation import interpolate_binary_search, interpolate_double_lookup
-
-
-def generate_target_points(E_min: float, E_max: float, num_points: int) -> np.ndarray:
-    """Generate target energy points with specified distribution."""
-    below_count = int(num_points * 0.225)  # 22.5% below minimum
-    above_count = int(num_points * 0.225)  # 22.5% above maximum
-    boundary_count = int(num_points * 0.05)  # 5% boundary points
-    inside_count = num_points - (below_count + above_count + boundary_count)
-
-    below_points = np.random.uniform(E_min - 1_000_000, E_min, size=below_count)
-    above_points = np.random.uniform(E_max, E_max + 1_000_000, size=above_count)
-    boundary_points = np.array([E_min, E_max] * (boundary_count // 2), dtype=np.float64)
-    inside_points = np.random.uniform(E_min, E_max, size=inside_count)
-
-    points = np.concatenate([
-        np.float64(inside_points),
-        np.float64(below_points),
-        np.float64(above_points),
-        boundary_points
-    ])
-    np.random.shuffle(points)
-    return points
-
-
-def compare_interpolation_methods(E_target: np.ndarray, T_eq: np.ndarray, E_neq: np.ndarray, E_eq: np.ndarray, inv_delta_E_eq: float, idx_mapping: np.ndarray, label: str = "") -> None:
-    """Compare binary search and double lookup interpolation methods."""
-    # E_eq = E_eq_from_E_neq(E_neq)
-    # idx_mapping = create_idx_mapping(E_neq, E_eq)
-
-    # Time binary search method
-    start_time_1 = time.perf_counter()
-    T_binary = [interpolate_binary_search(T_eq, float(E), E_neq) for E in E_target]
-    binary_time = time.perf_counter() - start_time_1
-
-    # Time double lookup method
-    start_time_2 = time.perf_counter()
-    T_double = [interpolate_double_lookup(float(E), T_eq, E_neq, E_eq, inv_delta_E_eq, idx_mapping)
-                for E in E_target]
-    double_time = time.perf_counter() - start_time_2
-
-    print(f"\nResults for {label}:")
-    print(f"Binary search time: {binary_time:.8f} s")
-    print(f"Double lookup time: {double_time:.8f} s")
-
-    # Check for mismatches
-    mismatches = [(E, T1, T2) for E, T1, T2 in zip(E_target, T_binary, T_double)
-                  if abs(T1 - T2) > 1e-8]
-
-    if mismatches:
-        print("Mismatches found (E_target, T_binary, T_double):")
-        for E, T1, T2 in mismatches[:5]:  # Show only first 5 mismatches
-            print(f"E={E:.8f}, T1={T1:.8f}, T2={T2:.8f}, diff={abs(T1-T2):.8f}")
-    else:
-        print("No mismatches found between methods")
-
-
-def create_alloy(T: Union[float, sp.Symbol]) -> Alloy:
-    alloy = Alloy(
-        elements=[Fe, Cr, Ni, Mo, Mn],
-        composition=[0.675, 0.17, 0.12, 0.025, 0.01],  # Fe: 67.5%, Cr: 17%, Ni: 12%, Mo: 2.5%, Mn: 1%
-        temperature_solidus=1653.15,  # Solidus temperature in Kelvin (test at 1653.15 K = 1380 C)
-        temperature_liquidus=1723.15,  # Liquidus temperature in Kelvin (test at 1723.15 K = 1450 C)
-        thermal_expansion_coefficient=16.3e-6  # in 1/K
-    )
-
-    # Determine the base directory
-    base_dir = Path(__file__).parent
-
-    # Paths to data files using relative paths
-    density_data_file_path = str(base_dir/'..'/'data'/'alloys'/'SS316L'/'density_temperature_edited.txt')
-    heat_capacity_data_file_path = str(base_dir/'..'/'data'/'alloys'/'SS316L'/'heat_capacity_temperature_edited.txt')
-
-    # Read temperature and material property data from the files
-    density_temp_array, density_array = read_data(density_data_file_path)
-    heat_capacity_temp_array, heat_capacity_array = read_data(heat_capacity_data_file_path)
-
-    # Ensure the data was loaded correctly
-    if any(arr.size < 2 for arr in [density_temp_array, density_array, heat_capacity_temp_array, heat_capacity_array]):
-        raise ValueError("Failed to load temperature or material data from the file.")
-
-    # Conversion: temperature to K and/or other material properties to SI units if necessary
-    density_temp_array = celsius_to_kelvin(density_temp_array)
-    density_array = thousand_times(density_array)  # Density in kg/m³ # gm/cm³ -> kg/m³
-    # plot_arrays(density_temp_array, density_array, "Temperature (K)", "Density (Kg/m^3)")
-    heat_capacity_temp_array = celsius_to_kelvin(heat_capacity_temp_array)
-    heat_capacity_array = thousand_times(heat_capacity_array)  # Specific heat capacity in J/(kg·K) # J/g-K -> J/kg-K
-    # plot_arrays(heat_capacity_temp_array, heat_capacity_array, "Temperature (K)", "Heat Capacity (J/Kg-K)")
-
-    alloy.density = interpolate_property(T, density_temp_array, density_array)
-    alloy.heat_capacity = interpolate_property(T, heat_capacity_temp_array, heat_capacity_array)
-    alloy.latent_heat_of_fusion = interpolate_property(T, alloy.solidification_interval(), np.array([0.0, 260000.0]))
-    alloy.energy_density = energy_density(T, alloy.density, alloy.heat_capacity, alloy.latent_heat_of_fusion)
-    print(alloy.energy_density.evalf(T, alloy.temperature_liquidus))
-
-    # print("alloy.density:", alloy.density, "type:", type(alloy.density))
-    # print("alloy.heat_capacity:", alloy.heat_capacity, "type:", type(alloy.heat_capacity))
-    # print("alloy.latent_heat_of_fusion:", alloy.latent_heat_of_fusion, "type:", type(alloy.latent_heat_of_fusion))
-    # print("alloy.energy_density:", alloy.energy_density, "type:", type(alloy.energy_density))
-
-    # Populate temperature_array and energy_density_array
-    alloy.temperature_array = density_temp_array
-
-    alloy.energy_density_array = np.array([
-        alloy.energy_density.evalf(T, temp) for temp in density_temp_array
-    ])
-    # print(alloy.temperature_array)
-    # print(alloy.energy_density_array)
-    # plot_arrays(alloy.temperature_array, alloy.energy_density_array, "Temperature (K)", "Energy Density (J/m^3)")
-
-    T_eq, E_neq, E_eq, inv_delta_E_eq, idx_map = prepare_interpolation_arrays(
-        alloy.temperature_array,
-        alloy.energy_density_array
-    )
-    # print(f"temperature_array:\n{T_eq}")
-    # print(f"energy_density_array:\n{E_neq}")
-
-    check_strictly_increasing(T_eq, "T_eq")
-    check_strictly_increasing(E_neq, "E_neq")
-
-    # Online execution
-    E = alloy.energy_density.evalf(T, alloy.temperature_liquidus)
-    print(E)
-
-    start_time1 = time.perf_counter()
-    T_interpolate1 = interpolate_binary_search(alloy.temperature_array, E, alloy.energy_density_array)
-    execution_time1 = time.perf_counter() - start_time1
-    print(f"Interpolated temperature: {T_interpolate1}")
-    print(f"Execution time: {execution_time1:.8f} seconds")
-
-    start_time2 = time.perf_counter()
-    T_interpolate2 = interpolate_binary_search(T_eq, E, E_neq)
-    execution_time2 = time.perf_counter() - start_time2
-    print(f"Interpolated temperature: {T_interpolate2}")
-    print(f"Execution time: {execution_time2:.8f} seconds")
-
-    start_time3 = time.perf_counter()
-    T_interpolate3 = interpolate_double_lookup(E, T_eq, E_neq, E_eq, inv_delta_E_eq, idx_map)
-    execution_time3 = time.perf_counter() - start_time3
-    print(f"Interpolated temperature: {T_interpolate3}")
-    print(f"Execution time: {execution_time3:.8f} seconds")
-
-    if not (T_interpolate1 == T_interpolate2 == T_interpolate3):
-        raise ValueError(f"Mismatch value. Temperature value should be {alloy.temperature_liquidus}")
-
-    E_target_alloy = generate_target_points(float(alloy.energy_density_array[0]), float(alloy.energy_density_array[-1]), 1_000)
-    compare_interpolation_methods(E_target_alloy, T_eq, E_neq, E_eq, inv_delta_E_eq, idx_map, 'SS316L')
-
-    def measure_performance(iterations=1):
-        all_execution_times = np.zeros(iterations)
-
-        for i in range(iterations):
-            start_measure_performance = time.perf_counter()
-
-            # Method 1: Binary Search
-            # results = [interpolate_binary_search(T_eq, E, E_neq) for E in E_target_alloy]
-
-            # Method 2: Double Lookup
-            results = [interpolate_double_lookup(E, T_eq, E_neq, E_eq, inv_delta_E_eq, idx_map) for E in E_target_alloy]
-
-            all_execution_times[i] = time.perf_counter() - start_measure_performance
-
-        # Calculate statistics using numpy
-        total_time = np.sum(all_execution_times)
-        avg_time = np.mean(all_execution_times)
-        avg_per_iteration = avg_time / len(E_target_alloy)
-
-        print(f"Total execution time ({iterations} runs): {total_time:.8f} seconds")
-        print(f"Average execution time per run: {avg_time:.8f} seconds")
-        print(f"Average execution time per iteration: {avg_per_iteration:.8f} seconds")
-
-    # Run the performance test
-    measure_performance(iterations=10_000)
-
-    return alloy
-
-
-if __name__ == '__main__':
-    Temp = sp.Symbol('T')
-    alloy = create_alloy(Temp)
-
-    # Test arrays
-    T_eq_small =  np.array([100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.], dtype=np.float64)
-    E_neq_small = np.array([1000., 1220., 1650., 2020., 2260., 2609., 3050., 3623., 3960., 4210.], dtype=np.float64)
-                                 #  0      1      2      3      4      5      6      7      8      9
-
-    # Equidistant energy array with delta_E_eq = 200 (smaller than min_delta = 220)
-    E_eq_small, inv_delta_E_eq_small = E_eq_from_E_neq(E_neq_small)
-    # E_eq = np.array([1000., 1209., 1418., 1627., 1836., 2045., 2254., 2463., 2672.,
-    #                  2881., 3090., 3299., 3508., 3717., 3926., 4135., 4344.])
-
-    # Index mapping array
-    idx_mapping_small = create_idx_mapping(E_neq_small, E_eq_small)
-    # idx_map = np.array([0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8])
-
-    # Test target energy values
-    E_target = 1.005*np.array([1000, 1585, 2688, 3960, 4210])
-    print(E_target)
-    for target in E_target:
-        T_star = interpolate_binary_search(T_eq_small, target, E_neq_small)
-        #print(T_star)
-        T_interpolate_double_lookup = interpolate_double_lookup(target, T_eq_small, E_neq_small, E_eq_small, inv_delta_E_eq_small, idx_mapping_small)
-        #print(T_interpolate_double_lookup)
-        if T_star != T_interpolate_double_lookup:
-            raise ValueError(f"Value Mismatch. {T_star} != {T_interpolate_double_lookup}")
-
-    E_target_small = generate_target_points(float(E_neq_small[0]), float(E_neq_small[-1]), 100)
-
-    compare_interpolation_methods(E_target_small, T_eq_small, E_neq_small, E_eq_small, inv_delta_E_eq_small, idx_mapping_small, "Small Dataset")
-
-
-    # Create larger test arrays
-    size = 1_000_000
-    T_eq_large = np.linspace(0.0, 1_000_000.0, size, dtype=np.float64)  # Equidistant temperature values
-    # Generate non-equidistant energy density array
-    # Using cumsum of random values ensures monotonically increasing values
-    E_neq_large = np.cumsum(np.random.uniform(1, 1_000, size)) + 1_000_000.0
-
-    E_eq_large, inv_delta_E_eq_large = E_eq_from_E_neq(E_neq_large)
-
-    idx_mapping_large = create_idx_mapping(E_neq_large, E_eq_large)
-
-    E_target_large = generate_target_points(float(E_neq_large[0]), float(E_neq_large[-1]), 1_000_000)
-
-    compare_interpolation_methods(E_target_large, T_eq_large, E_neq_large, E_eq_large, inv_delta_E_eq_large, idx_mapping_large, "Large Dataset")
diff --git a/tests/cpp/CMakeLists.txt b/tests/cpp/CMakeLists.txt
new file mode 100644
index 0000000..68801ca
--- /dev/null
+++ b/tests/cpp/CMakeLists.txt
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 3.10)
+project(pymatlib_tests)
+
+# Find required packages
+find_package(Python COMPONENTS Interpreter Development NumPy REQUIRED)
+execute_process(
+        COMMAND ${Python_EXECUTABLE} -m pybind11 --cmakedir
+        OUTPUT_VARIABLE PYBIND11_CMAKE_DIR
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+find_package(pybind11 PATHS ${PYBIND11_CMAKE_DIR} NO_DEFAULT_PATH REQUIRED)
+
+# Get the path to the source directory
+set(SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../src/pymatlib/core/cpp")
+
+# Create interface library for header-only template implementation
+add_library(interpolation_template INTERFACE)
+target_include_directories(interpolation_template INTERFACE
+        ${SRC_DIR}
+        ${SRC_DIR}/include
+)
+
+# Add C++ test executable
+add_executable(fast_interpolation_test_cpp test_interpolation.cpp)
+target_include_directories(fast_interpolation_test_cpp PRIVATE
+        ${SRC_DIR}
+        ${SRC_DIR}/include
+)
+target_compile_features(fast_interpolation_test_cpp PRIVATE cxx_std_11)
+target_compile_options(fast_interpolation_test_cpp PRIVATE -O3)
+target_link_libraries(fast_interpolation_test_cpp PRIVATE
+        interpolation_template
+)
+
+# Optional: Add custom target for running Python tests if you have a Python test file
+# add_custom_target(fast_interpolation_test_py
+#         COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_interpolation.py
+#         DEPENDS fast_interpolation_test_cpp
+#         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+#         COMMENT "Running Python tests"
+# )
diff --git a/src/pymatlib/core/cpp/TestArrayContainer.py b/tests/cpp/TestArrayContainer.py
similarity index 100%
rename from src/pymatlib/core/cpp/TestArrayContainer.py
rename to tests/cpp/TestArrayContainer.py
diff --git a/src/pymatlib/core/cpp/test_interpolation.cpp b/tests/cpp/test_interpolation.cpp
similarity index 100%
rename from src/pymatlib/core/cpp/test_interpolation.cpp
rename to tests/cpp/test_interpolation.cpp
diff --git a/tests/legacy/__init__.py b/tests/legacy/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/legacy/test_interpolate_functs_perf.py b/tests/legacy/test_interpolate_functs_perf.py
index 7aa39d4..b9266a8 100644
--- a/tests/legacy/test_interpolate_functs_perf.py
+++ b/tests/legacy/test_interpolate_functs_perf.py
@@ -1,3 +1,20 @@
+"""
+DEPRECATED: This file contains the original implementation of interpolation comparision.
+It is kept for historical reference only and should not be used in new code.
+
+As of March 2025, please use the new dictionary-based implementation in
+pymatlib.core.interpolators instead.
+"""
+
+import warnings
+
+warnings.warn(
+    "This module is deprecated and will be removed in a future version. "
+    "Please use pymatlib.core.interpolators instead.",
+    DeprecationWarning,
+    stacklevel=2
+)
+
 import time
 import numpy as np
 import sympy as sp
diff --git a/tests/python/__init__.py b/tests/python/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_alloy.py b/tests/python/test_alloy.py
similarity index 100%
rename from tests/test_alloy.py
rename to tests/python/test_alloy.py
diff --git a/tests/test_assignment_converter.py b/tests/python/test_assignment_converter.py
similarity index 100%
rename from tests/test_assignment_converter.py
rename to tests/python/test_assignment_converter.py
diff --git a/tests/test_data_handler.py b/tests/python/test_data_handler.py
similarity index 100%
rename from tests/test_data_handler.py
rename to tests/python/test_data_handler.py
diff --git a/src/pymatlib/core/cpp/test_interpolation.py b/tests/python/test_interpolation.py
similarity index 100%
rename from src/pymatlib/core/cpp/test_interpolation.py
rename to tests/python/test_interpolation.py
diff --git a/tests/test_interpolators.py b/tests/python/test_interpolators.py
similarity index 100%
rename from tests/test_interpolators.py
rename to tests/python/test_interpolators.py
diff --git a/tests/test_models.py b/tests/python/test_models.py
similarity index 100%
rename from tests/test_models.py
rename to tests/python/test_models.py
diff --git a/tests/test_typedefs.py b/tests/python/test_typedefs.py
similarity index 100%
rename from tests/test_typedefs.py
rename to tests/python/test_typedefs.py
diff --git a/src/pymatlib/data/alloys/SS316L/test_yaml_config.py b/tests/python/test_yaml_config.py
similarity index 89%
rename from src/pymatlib/data/alloys/SS316L/test_yaml_config.py
rename to tests/python/test_yaml_config.py
index a106f0f..d370993 100644
--- a/src/pymatlib/data/alloys/SS316L/test_yaml_config.py
+++ b/tests/python/test_yaml_config.py
@@ -12,8 +12,12 @@ def print_property_value(prop, T, temp):
 # Create symbolic temperature variable
 T = sp.Symbol('T')
 
+# Get the path to the YAML file
+current_file = Path(__file__)
+yaml_path = current_file.parent.parent.parent / "src" / "pymatlib" / "data" / "alloys" / "SS316L" / "SS304L.yaml"
+
 # Create alloy from YAML
-ss316l = create_alloy_from_yaml("SS304L.yaml", T)
+ss316l = create_alloy_from_yaml(yaml_path, T)
 #ss316l_1 = create_alloy_from_yaml("SS304L_1.yaml", T)
 
 # Test various properties
-- 
GitLab