diff --git a/run_tests.py b/run_all_tests.py similarity index 100% rename from run_tests.py rename to run_all_tests.py diff --git a/src/pymatlib/core/models.py b/src/pymatlib/core/models.py index eb04608727cc7e51370f00353fa19a4943410807..6c54a9db2d0cc1e96e087b1c5fec119c20b62eb6 100644 --- a/src/pymatlib/core/models.py +++ b/src/pymatlib/core/models.py @@ -1,26 +1,29 @@ import numpy as np import sympy as sp -from typing import Union, List, Tuple, get_args, TypeVar +from typing import Union, List, TypeVar from pymatlib.core.typedefs import MaterialProperty, ArrayTypes # Type variables for more specific type hints NumericType = TypeVar('NumericType', float, np.float32, np.float64) # Constants -ABSOLUTE_ZERO = -273.15 # Celsius +ABSOLUTE_ZERO = 0.0 # Kelvin DEFAULT_TOLERANCE = 1e-10 def validate_density_parameters( temperature: Union[float, ArrayTypes, sp.Expr], + temperature_base: float, density_base: float, thermal_expansion_coefficient: Union[float, MaterialProperty]) -> None: """ Validate physical quantities for density calculation. """ + if temperature_base < ABSOLUTE_ZERO: + raise ValueError(f"Base temperature cannot be below absolute zero ({ABSOLUTE_ZERO}K)") if isinstance(temperature, float): if temperature < ABSOLUTE_ZERO: - raise ValueError(f"Temperature cannot be below absolute zero ({ABSOLUTE_ZERO}°C)") + raise ValueError(f"Temperature cannot be below absolute zero ({ABSOLUTE_ZERO}K)") elif isinstance(temperature, ArrayTypes): temp_array = np.asarray(temperature) if np.any(temp_array < ABSOLUTE_ZERO): @@ -29,8 +32,8 @@ def validate_density_parameters( if density_base <= 0: raise ValueError("Base density must be positive") - if isinstance(thermal_expansion_coefficient, float) and thermal_expansion_coefficient <= -1: - raise ValueError("Thermal expansion coefficient must be greater than -1") + if isinstance(thermal_expansion_coefficient, float) and thermal_expansion_coefficient < -3e-5: + raise ValueError("Thermal expansion coefficient must be greater than -3e-5") def validate_thermal_diffusivity_parameters( heat_conductivity: Union[float, MaterialProperty], @@ -121,7 +124,7 @@ def density_by_thermal_expansion( from pymatlib.core.interpolators import interpolate_property if validate: - validate_density_parameters(temperature, density_base, thermal_expansion_coefficient) + validate_density_parameters(temperature, temperature_base, density_base, thermal_expansion_coefficient) if isinstance(temperature, ArrayTypes): temperature = np.asarray(temperature) diff --git a/src/pymatlib/core/typedefs.py b/src/pymatlib/core/typedefs.py index f6b69cd4a2cbe01d72c12489f43d0a891f4dfabd..fcebd9a9ba69178f8d0f87b7cb904eb361998058 100644 --- a/src/pymatlib/core/typedefs.py +++ b/src/pymatlib/core/typedefs.py @@ -91,23 +91,20 @@ class MaterialProperty: - temperature contains non-numeric values - invalid type for temperature """ - # Get all symbols from expression and assignments - expr_symbols = self.expr.free_symbols - assignment_symbols = set().union(*( - assignment.rhs.free_symbols - for assignment in self.assignments - if isinstance(assignment.rhs, sp.Expr) - )) - all_symbols = expr_symbols.union(assignment_symbols) + # If the expression has no symbolic variables, return it as a constant float + if not self.expr.free_symbols: + return float(self.expr) + # Collect all relevant symbols from expressions and assignments + all_symbols = self.expr.free_symbols.union( + *(assignment.rhs.free_symbols + for assignment in self.assignments + if isinstance(assignment.rhs, sp.Expr)) + ) # If we have symbols but the provided one isn't among them, raise TypeError if all_symbols and symbol not in all_symbols: raise TypeError(f"Symbol {symbol} not found in expression or assignments") - # If the expression has no symbolic variables, return it as a constant float - if not self.expr.free_symbols: - return float(self.expr) - # Handle array inputs # If temperature is a numpy array, list, or tuple (ArrayTypes), evaluate the property for each temperature if isinstance(temperature, get_args(ArrayTypes)): @@ -144,148 +141,3 @@ class MaterialProperty: # Type alias for properties that can be either constant floats or MaterialProperty instances PropertyTypes = Union[float, MaterialProperty] - -if __name__ == '__main__': - # Example usage and tests for MaterialProperty and Assignment classes - - T = sp.Symbol('T') - v = sp.IndexedBase('v') - i = sp.Symbol('i', type=sp.Integer) - - # Example 1: Constant material property - mp0 = MaterialProperty(sp.Float(405.)) - mp0.assignments.append(Assignment(sp.Symbol('A'), (100, 200), 'int')) - print(mp0) - print(mp0.evalf(T, 100.)) - - # Example 2: Linear temperature-dependent property - mp1 = MaterialProperty(T * 100.) - print(mp1) - print(mp1.evalf(T, 100.)) - - # Example 3: Indexed base with symbolic assignments - mp2 = MaterialProperty(v[i]) - mp2.assignments.append(Assignment(v, (3, 6, 9), 'float')) - mp2.assignments.append(Assignment(i, T / 100, 'int')) - print(mp2) - print(mp2.evalf(T, 97)) # Should evaluate with i=0 (since 97/100 is 0 when converted to int) - print(mp2.evalf(T, 107)) # Should evaluate with i=1 (since 107/100 is 1 when converted to int) - - # Example 4: Evaluate an expression with an array of temperatures - rho = 1e-6 * T ** 3 * 4000 - print(rho * np.array([10, 20, 30])) - -if __name__ == '__main__': - # Example usage and tests for MaterialProperty and Assignment classes - - T = sp.Symbol('T') - v = sp.IndexedBase('v') - i = sp.Symbol('i', type=sp.Integer) - - # Test 1: Constant material property - mp0 = MaterialProperty(sp.Float(405.)) - mp0.assignments.append(Assignment(sp.Symbol('A'), (100, 200), 'int')) - print(f"Test 1 - Constant property, no symbolic variables: {mp0.evalf(T, 100.)}") # Expected output: 405.0 - - # Test 2: Linear temperature-dependent property - mp1 = MaterialProperty(T * 100.) - print(f"Test 2 - Linear temperature-dependent property: {mp1.evalf(T, 100.)}") # Expected output: 10000.0 - - # Test 3: Indexed base with symbolic assignments - mp2 = MaterialProperty(v[i]) - mp2.assignments.append(Assignment(v, (3, 6, 9), 'float')) - mp2.assignments.append(Assignment(i, T / 100, 'int')) - print(f"Test 3a - Indexed base with i=0: {mp2.evalf(T, 97)}") # Expected output: 3 (i=0) - print(f"Test 3b - Indexed base with i=1: {mp2.evalf(T, 107)}") # Expected output: 6 (i=1) - - # Test 4: Evaluate an expression with an array of temperatures - rho = 1e-6 * T ** 3 * 4000 - temps = np.array([10, 20, 30]) - print(f"Test 4 - Expression evaluated with array: {rho * temps}") # Expected output: array of evaluated values - - # Additional Tests: - - # Test 5: Non-linear temperature-dependent property - mp3 = MaterialProperty(T ** 2 + T * 50 + 25) - print(f"Test 5 - Non-linear temperature-dependent property: {mp3.evalf(T, 10)}") # Expected output: 625.0 - - # Test 6: Temperature array evaluation for non-linear expression - print(f"Test 6 - Non-linear property with temperature array: {mp3.evalf(T, temps)}") - # Expected output: array of evaluated values for T in [10, 20, 30] - - # Test 7: Property with multiple symbolic assignments - mp4 = MaterialProperty(v[i] * T) - mp4.assignments.append(Assignment(v, (3, 6, 9), 'float')) - mp4.assignments.append(Assignment(i, T / 100, 'int')) - print(f"Test 7a - Property with multiple symbolic assignments at T=95: {mp4.evalf(T, 95)}") # Expected: 285.0 - print(f"Test 7b - Property with multiple symbolic assignments at T=205: {mp4.evalf(T, 205)}") # Expected: 1230.0 - - # Test 8: Constant property evaluated with temperature array - mp5 = MaterialProperty(sp.Float(500.)) - print(f"Test 8 - Constant property with temperature array: {mp5.evalf(T, temps)}") - # Expected output: array of 500s for each temperature - - # Test 9: Handling numpy scalar input - scalar_temp = np.float64(150.0) - mp6 = MaterialProperty(T + 50) - print(f"Test 9 - Handling numpy scalar input: {mp6.evalf(T, scalar_temp)}") # Expected output: 200.0 - - # Test 10: Property with no symbolic dependencies - mp7 = MaterialProperty(sp.Float(1500.)) - print(f"Test 10 - Property with no symbolic dependencies: {mp7.evalf(T, 200.)}") # Expected output: 1500.0 - - # Test 11: Piecewise function - mp8 = MaterialProperty(sp.Piecewise((100, T < 0), (200, T >= 100), (T, True))) - print(f"Test 11a - Piecewise function at T=-10: {mp8.evalf(T, -10)}") # Expected: 100 - print(f"Test 11b - Piecewise function at T=50: {mp8.evalf(T, 50)}") # Expected: 50 - print(f"Test 11c - Piecewise function at T=150: {mp8.evalf(T, 150)}") # Expected: 200 - - # Test 12: Complex expression with trigonometric functions - mp9 = MaterialProperty(100 * sp.sin(T) + 50 * sp.cos(T)) - print(f"Test 12a - Complex expression at T=0: {mp9.evalf(T, 0)}") # Expected: 50 - print(f"Test 12b - Complex expression at T=pi/2: {mp9.evalf(T, np.pi/2)}") # Expected: 100 - - # Test 13: Expression with logarithmic and exponential functions - mp10 = MaterialProperty(10 * sp.log(T + 1) + 5 * sp.exp(T/100)) - print(f"Test 13 - Log and exp expression at T=10: {mp10.evalf(T, 10)}") # Expected: ~28.19 - - # Test 14: Property with multiple variables - T2 = sp.Symbol('T2') - mp11 = MaterialProperty(T * T2) - res = mp11.evalf(T, 10) - print(f"Test 14 - Multi-variable property: {res}") # This should raise an error or return a symbolic expression - assert isinstance(res, sp.Expr) - assert sp.Eq(res, 10 * T2) - - # Test 15: Handling very large and very small numbers - mp12 = MaterialProperty(1e20 * T + 1e-20) - print(f"Test 15a - Large numbers: {mp12.evalf(T, 1e5)}") - print(f"Test 15b - Small numbers: {mp12.evalf(T, 1e-5)}") - - # Test 16: Property with rational functions - mp13 = MaterialProperty((T**2 + 1) / (T + 2)) - print(f"Test 16 - Rational function at T=3: {mp13.evalf(T, 3)}") - - # Test 17: Handling undefined values (division by zero) - mp14 = MaterialProperty(1 / (T - 1)) - try: - res = mp14.evalf(T, 1) - print(f"Test 17 - Division by zero at T=1: {res}") # "zoo" in SymPy represents complex infinity - except ZeroDivisionError: - print("Test 17 - Division by zero at T=1: ZeroDivisionError raised as expected") - - # Test 18: Property with absolute value - mp15 = MaterialProperty(sp.Abs(T - 50)) - print(f"Test 18a - Absolute value at T=30: {mp15.evalf(T, 30)}") - print(f"Test 18b - Absolute value at T=70: {mp15.evalf(T, 70)}") - - # Test 19: Property with floor and ceiling functions - mp16 = MaterialProperty(sp.floor(T/10) + sp.ceiling(T/10)) - print(f"Test 19 - Floor and ceiling at T=25: {mp16.evalf(T, 25)}") - - # Test 20: Handling complex numbers - mp17 = MaterialProperty(sp.sqrt(T)) - print(f"Test 20a - Square root at T=4: {mp17.evalf(T, 4)}") - res = mp17.evalf(T, -1) - print(f"Test 20b - Square root at T=-1: {res}") - assert isinstance(res, sp.Expr) diff --git a/tests/test_alloy.py b/tests/test_alloy.py index ea4ff3f455c97b3a6f86f5fa899d4ae8512f3b26..b6550483d5d5da44856774b50148d761273c1fa8 100644 --- a/tests/test_alloy.py +++ b/tests/test_alloy.py @@ -1,7 +1,87 @@ import pytest import numpy as np +import sympy as sp from pymatlib.core.alloy import Alloy, AlloyCompositionError, AlloyTemperatureError -from pymatlib.data.element_data import Ti, Al, V +from pymatlib.data.element_data import Ti, Al, V, Fe, Cr, Mn, Ni +from src.pymatlib.data.alloys.SS316L.SS316L import create_SS316L +from src.pymatlib.core.typedefs import MaterialProperty + +def test_alloy_creation(): + # Test creating an alloy with valid elemental composition and phase transition temperatures + alloy = Alloy(elements=[Fe, Cr, Mn, Ni], composition=[0.7, 0.2, 0.05, 0.05], temperature_solidus=1700, temperature_liquidus=1800) + assert np.allclose(alloy.composition, [0.7, 0.2, 0.05, 0.05]) + assert alloy.temperature_solidus == 1700. + assert alloy.temperature_liquidus == 1800. + + # Test creating an alloy with invalid elemental composition + with pytest.raises(ValueError): + Alloy(elements=[Fe, Cr], composition=[0.6, 0.5], temperature_solidus=1700., temperature_liquidus=1800.) + + # Test creating an alloy with invalid phase transition temperatures + with pytest.raises(ValueError): + Alloy(elements=[Fe, Cr, Mn, Ni], composition=[0.7, 0.2, 0.05, 0.05], temperature_solidus=1900., temperature_liquidus=1800.) + +def test_create_SS316L(): + """Test the creation and properties of SS316L alloy.""" + # Test with float temperature input + alloy = create_SS316L(1400.0) + + # Check if properties are set and have correct types + assert hasattr(alloy, 'density') + assert hasattr(alloy, 'heat_capacity') + assert hasattr(alloy, 'heat_conductivity') + assert hasattr(alloy, 'thermal_diffusivity') + + # Check if properties have correct values and types + assert alloy.density is not None + assert alloy.heat_capacity is not None + assert alloy.heat_conductivity is not None + assert alloy.thermal_diffusivity is not None + + # Test with symbolic temperature input + T = sp.Symbol('T') + alloy_symbolic = create_SS316L(T) + + # Check symbolic properties + assert alloy_symbolic.density is not None + assert alloy_symbolic.heat_capacity is not None + assert alloy_symbolic.heat_conductivity is not None + assert alloy_symbolic.thermal_diffusivity is not None + + # Test property values + assert isinstance(float(alloy.density.expr), float) + assert isinstance(float(alloy.heat_capacity.expr), float) + assert isinstance(float(alloy.heat_conductivity.expr), float) + assert isinstance(float(alloy.thermal_diffusivity.expr), float) + +def test_create_SS316L2(): + alloy = create_SS316L(1400.0) + + # Check if density exists and has the correct type + assert hasattr(alloy, 'density') + assert alloy.density is not None + assert type(alloy.density).__name__ == "MaterialProperty", f"Expected MaterialProperty, got {type(alloy.density)}" + +def test_alloy_single_element(): + # Test creating an alloy with a single element + alloy = Alloy(elements=[Fe], composition=[1.0], temperature_solidus=1800, temperature_liquidus=1900) + assert len(alloy.elements) == 1 + assert alloy.composition == [1.0] + +def test_alloy_property_modification(): + # Test accessing and modifying individual alloy properties + alloy = create_SS316L(1400.0) + # assert isinstance(alloy.density, MaterialProperty) + # Set the density to a MaterialProperty instance with a constant expression + alloy.density = MaterialProperty(expr=sp.Float(8000.0)) + assert alloy.density.expr == sp.Float(8000.0) + +def test_create_SS316L_invalid_temperature(): + # Test creating SS316L alloy with invalid temperature inputs + with pytest.raises(ValueError): + create_SS316L(-100.0) # Negative temperature + with pytest.raises(ValueError): + create_SS316L(3500.0) # Temperature outside valid range def test_valid_alloy(): Ti64 = Alloy([Ti, Al, V], [0.90, 0.06, 0.04], 1878, 1928) diff --git a/tests/test_assignment_converter.py b/tests/test_assignment_converter.py index f8a206693a9e230d02aceddf208cbe45c18ab6fb..841b47a20757d299cb6974ec10e2aa5b196719c4 100644 --- a/tests/test_assignment_converter.py +++ b/tests/test_assignment_converter.py @@ -67,4 +67,15 @@ def test_invalid_assignments(): # Test with missing type x = sp.Symbol('x') with pytest.raises(ValueError): - assignment_converter([Assignment(x, sp.Symbol('value_x'), None)]) \ No newline at end of file + assignment_converter([Assignment(x, sp.Symbol('value_x'), None)]) + +def test_type_mapping_unsupported(): + # Test mapping unsupported type strings + with pytest.raises(ValueError): + type_mapping("unsupported_type", 1) + +def test_assignment_converter_invalid(): + # Test converting assignments with invalid or missing attributes + invalid_assignment = Assignment(lhs=None, rhs=None, lhs_type=None) + with pytest.raises(ValueError, match="Invalid assignment: lhs, rhs, and lhs_type must not be None"): + assignment_converter([invalid_assignment]) diff --git a/tests/test_interpolators.py b/tests/test_interpolators.py index 0b01914984cd6c63842b10b5e13ae19e30d42236..913437c7a48722375902274fd6e81c48e0e850d7 100644 --- a/tests/test_interpolators.py +++ b/tests/test_interpolators.py @@ -141,4 +141,152 @@ def test_interpolate_property(): interpolate_property(350.0, 123, v_array) # Invalid temp_array type with pytest.raises(ValueError): - interpolate_property(350.0, temp_array, v_array[:-1]) # Mismatched lengths \ No newline at end of file + interpolate_property(350.0, temp_array, v_array[:-1]) # Mismatched lengths + +def test_interpolate_property1(): + # Test interpolating properties with float temperature inputs + T_symbol = sp.Symbol('T') # Define a symbolic variable + T_value = 1400.0 + temp_array = np.array([1300.0, 1400.0, 1500.0]) + prop_array = np.array([100.0, 200.0, 300.0]) + result = interpolate_property(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + # Test interpolating properties with symbolic temperature inputs + result = interpolate_property(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + # Test interpolating properties with different combinations of temperature and property arrays + temp_array = [1300.0, 1400.0, 1500.0] + prop_array = [100.0, 200.0, 300.0] + result = interpolate_property(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + temp_array = tuple([1300.0, 1400.0, 1500.0]) + prop_array = tuple([100.0, 200.0, 300.0]) + result = interpolate_property(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + # Test with ascending and descending order arrays + temp_array_asc = np.array([1300.0, 1400.0, 1500.0]) + prop_array_asc = np.array([100.0, 200.0, 300.0]) + result_asc = interpolate_property(T_symbol, temp_array_asc, prop_array_asc) + assert isinstance(result_asc, MaterialProperty) + + temp_array_desc = np.array([1500.0, 1400.0, 1300.0]) + prop_array_desc = np.array([300.0, 200.0, 100.0]) + result_desc = interpolate_property(T_symbol, temp_array_desc, prop_array_desc) + assert isinstance(result_desc, MaterialProperty) + + # Test with different temp_array_limit values + result_limit_6 = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, temp_array_limit=6) + assert isinstance(result_limit_6, MaterialProperty) + + result_limit_3 = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, temp_array_limit=3) + assert isinstance(result_limit_3, MaterialProperty) + + # Test with force_lookup True and False + result_force_lookup_true = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, force_lookup=True) + assert isinstance(result_force_lookup_true, MaterialProperty) + + result_force_lookup_false = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, force_lookup=False) + assert isinstance(result_force_lookup_false, MaterialProperty) + # assert np.isclose(result_force_lookup_false.evalf(T_symbol, T_value), 200.0) + +def test_interpolate_lookup1(): + # Define a symbolic variable + T_symbol = sp.Symbol('T') + + # Test lookup interpolation with float temperature inputs + T_value = 1400.0 + temp_array = np.array([1300.0, 1400.0, 1500.0]) + prop_array = np.array([100.0, 200.0, 300.0]) + result = interpolate_lookup(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + # Test lookup interpolation with symbolic temperature inputs + result = interpolate_lookup(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + # Test with different combinations of temperature and property arrays + temp_array = [1300.0, 1400.0, 1500.0] + prop_array = [100.0, 200.0, 300.0] + result = interpolate_lookup(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + temp_array = tuple([1300.0, 1400.0, 1500.0]) + prop_array = tuple([100.0, 200.0, 300.0]) + result = interpolate_lookup(T_symbol, temp_array, prop_array) + assert isinstance(result, MaterialProperty) + + # Test with ascending and descending order arrays + temp_array_asc = np.array([1300.0, 1400.0, 1500.0]) + prop_array_asc = np.array([100.0, 200.0, 300.0]) + result_asc = interpolate_lookup(T_symbol, temp_array_asc, prop_array_asc) + assert isinstance(result_asc, MaterialProperty) + + temp_array_desc = np.array([1500.0, 1400.0, 1300.0]) + prop_array_desc = np.array([300.0, 200.0, 100.0]) + result_desc = interpolate_lookup(T_symbol, temp_array_desc, prop_array_desc) + assert isinstance(result_desc, MaterialProperty) + # assert np.isclose(result_desc.evalf(T_symbol, T_value), 200.0) + +def test_interpolate_equidistant1(): + # Define a symbolic variable + T_symbol = sp.Symbol('T') + + # Test equidistant interpolation with float temperature inputs + T_value = 1400.0 + temp_base = 1300.0 + temp_incr = 100.0 + prop_array = np.array([100.0, 200.0, 300.0]) + result = interpolate_equidistant(T_value, temp_base, temp_incr, prop_array) + assert isinstance(result, MaterialProperty) + + # Test equidistant interpolation with symbolic temperature inputs + result = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array) + assert isinstance(result, MaterialProperty) + assert np.isclose(result.evalf(T_symbol, T_value), 200.0) + + # Test with different combinations of temperature and property arrays + temp_base = 1300.0 + temp_incr = 100.0 + prop_array = [100.0, 200.0, 300.0] + result = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array) + assert isinstance(result, MaterialProperty) + assert np.isclose(result.evalf(T_symbol, T_value), 200.0) + + temp_base = 1300.0 + temp_incr = 100.0 + prop_array = tuple([100.0, 200.0, 300.0]) + result = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array) + assert isinstance(result, MaterialProperty) + assert np.isclose(result.evalf(T_symbol, T_value), 200.0) + + # Test with ascending and descending order arrays + temp_base = 1300.0 + temp_incr = 100.0 + prop_array_asc = np.array([100.0, 200.0, 300.0]) + result_asc = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array_asc) + assert isinstance(result_asc, MaterialProperty) + assert np.isclose(result_asc.evalf(T_symbol, T_value), 200.0) + + temp_base = 1300.0 + temp_incr = 100.0 + prop_array_desc = np.array([300.0, 200.0, 100.0]) + result_desc = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array_desc) + assert isinstance(result_desc, MaterialProperty) + assert np.isclose(result_desc.evalf(T_symbol, T_value), 200.0) + +# Define the temp fixture +@pytest.fixture +def temp(): + return np.array([100.0, 200.0, 300.0, 400.0, 500.0]) + +def test_test_equidistant(temp): + # Test with equidistant temperature array + assert check_equidistant(temp) == 100.0 + + # Test with non-equidistant temperature array + temp_non_equidistant = np.array([100.0, 150.0, 300.0, 450.0, 500.0]) + assert check_equidistant(temp_non_equidistant) == 0.0 diff --git a/tests/test_models.py b/tests/test_models.py index eeb485081ac39de41cc50d43d9c844b949e6c44a..9dabc870cac0e94830a002fc3c61942816404fcd 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -14,19 +14,19 @@ from pymatlib.core.typedefs import MaterialProperty def test_validate_density_parameters(): """Test density parameter validation.""" # Valid parameters - validate_density_parameters(300.0, 8000.0, 1e-6) + validate_density_parameters(300.0, 1000.0, 8000.0, 1e-6) # Test temperature validation with pytest.raises(ValueError, match="Temperature cannot be below absolute zero"): - validate_density_parameters(-274.0, 8000.0, 1e-6) + validate_density_parameters(-274.0, 1000., 8000.0, 1e-6) # Test density validation with pytest.raises(ValueError, match="Base density must be positive"): - validate_density_parameters(300.0, -8000.0, 1e-6) + validate_density_parameters(300.0, 1000., -8000.0, 1e-6) # Test thermal expansion coefficient validation - with pytest.raises(ValueError, match="Thermal expansion coefficient must be greater than -1"): - validate_density_parameters(300.0, 8000.0, -1.5) + with pytest.raises(ValueError, match="Thermal expansion coefficient must be greater than -3e-5"): + validate_density_parameters(300.0, 1000, 8000.0, -1.5) def test_validate_thermal_diffusivity_parameters(): """Test thermal diffusivity parameter validation.""" @@ -175,3 +175,74 @@ def test_models(): # Test assignment combination assert hasattr(result, 'assignments') + +def test_density_by_thermal_expansion1(): + """Test calculating density with various inputs.""" + + # Test with float inputs + T = 1400.0 + T_ref = 1000.0 + rho_ref = 8000.0 + alpha = 1e-5 + + result = density_by_thermal_expansion(T, T_ref, rho_ref, alpha) + assert np.isclose(result.expr, 7904.762911) # Ensure this expected value is correct + + # Test with symbolic temperature input + T_symbolic = sp.Symbol('T') + result_sym = density_by_thermal_expansion(T_symbolic, T_ref, rho_ref, alpha) + assert isinstance(result_sym, MaterialProperty) + assert np.isclose(result_sym.evalf(T_symbolic, T), 7904.76) + + # Test with numpy array for temperature input + T_array = np.array([1300.0, 1400.0, 1500.0]) + result_array = density_by_thermal_expansion(T_array, T_ref, rho_ref, alpha) + assert isinstance(result_array, MaterialProperty) + + # Test edge cases with negative values + with pytest.raises(ValueError): + density_by_thermal_expansion(-100.0, T_ref, rho_ref, alpha) # Invalid temperature + + with pytest.raises(ValueError): + density_by_thermal_expansion(T, T_ref, -8000.0, alpha) # Invalid density + + with pytest.raises(ValueError): + density_by_thermal_expansion(T, T_ref, rho_ref, -1e-4) # Invalid thermal expansion coefficient + +def test_thermal_diffusivity_by_heat_conductivity1(): + # Test calculating thermal diffusivity with float heat conductivity, density, and heat capacity inputs + k = 50.0 + rho = 8000.0 + c_p = 500.0 + result = thermal_diffusivity_by_heat_conductivity(k, rho, c_p) + assert np.isclose(result.expr, 1.25e-5) + + # Test calculating thermal diffusivity with symbolic heat conductivity, density, and heat capacity inputs + k = sp.Symbol('k') + rho = sp.Symbol('rho') + c_p = sp.Symbol('c_p') + result = thermal_diffusivity_by_heat_conductivity(k, rho, c_p) + assert isinstance(result, MaterialProperty) + assert result.expr == k / (rho * c_p) + +def test_density_by_thermal_expansion_invalid_inputs(): + # Test calculating density with invalid temperature or thermal expansion coefficient inputs + with pytest.raises(ValueError): + density_by_thermal_expansion(-100.0, 1000.0, 8000.0, 1e-5) + with pytest.raises(ValueError): + density_by_thermal_expansion(1000.0, -1000.0, 8000.0, 1e-5) + with pytest.raises(ValueError): + density_by_thermal_expansion(1000.0, 1000.0, -8000.0, 1e-5) + with pytest.raises(ValueError): + density_by_thermal_expansion(1000.0, 1000.0, 8000.0, -1e-4) + with pytest.raises(ValueError): + density_by_thermal_expansion(np.array([-100.0, 1000.0]), 1000.0, 8000.0, 1e-5) + +def test_thermal_diffusivity_invalid_inputs(): + # Test calculating thermal diffusivity with invalid heat conductivity, density, or heat capacity inputs + with pytest.raises(ValueError): + thermal_diffusivity_by_heat_conductivity(-10.0, 8000.0, 500.0) # Negative heat conductivity + with pytest.raises(ValueError): + thermal_diffusivity_by_heat_conductivity(50.0, -8000.0, 500.0) # Negative density + with pytest.raises(ValueError): + thermal_diffusivity_by_heat_conductivity(50.0, 8000.0, -500.0) # Negative heat capacity diff --git a/tests/test_typedefs.py b/tests/test_typedefs.py index dfbbb318f312995c0bb4a414286915a4f6073729..0c91e27325050c754c00b669f020e6259bc868c3 100644 --- a/tests/test_typedefs.py +++ b/tests/test_typedefs.py @@ -1,7 +1,7 @@ import pytest import numpy as np import sympy as sp -from pymatlib.core.typedefs import Assignment, MaterialProperty, ArrayTypes, PropertyTypes +from pymatlib.core.typedefs import Assignment, MaterialProperty def test_assignment(): """Test Assignment dataclass functionality.""" @@ -21,26 +21,14 @@ def test_assignment(): def test_material_property_constant(): """Test MaterialProperty with constant values.""" - # Test constant property mp = MaterialProperty(sp.Float(405.)) - assert mp.evalf(sp.Symbol('T'), 100.) == 405.0 + assert mp.evalf(sp.Symbol('T'), 100.) == 405.0 # Expected output: 405.0 - # Test with assignments - mp.assignments.append(Assignment(sp.Symbol('A'), (100, 200), 'int')) - assert isinstance(mp.assignments, list) - assert len(mp.assignments) == 1 - -def test_material_property_temperature_dependent(): - """Test MaterialProperty with temperature-dependent expressions.""" +def test_material_property_linear(): + """Test MaterialProperty with linear temperature-dependent property.""" T = sp.Symbol('T') - - # Test linear dependency mp = MaterialProperty(T * 100.) - assert mp.evalf(T, 2.0) == 200.0 - - # Test polynomial - mp = MaterialProperty(T**2 + T + 1) - assert mp.evalf(T, 2.0) == 7.0 + assert mp.evalf(T, 100.) == 10000.0 # Expected output: 10000.0 def test_material_property_indexed(): """Test MaterialProperty with indexed base expressions.""" @@ -49,13 +37,15 @@ def test_material_property_indexed(): i = sp.Symbol('i', integer=True) mp = MaterialProperty(v[i]) + + # Assignments should include how i is determined mp.assignments.extend([ Assignment(v, (3, 6, 9), 'float'), - Assignment(i, T / 100, 'int') + Assignment(i, T / 100, 'int') # i is determined by T ]) - assert mp.evalf(T, 97) == 3 # i=0 - assert mp.evalf(T, 150) == 6 # i=1 + # Evaluate at a temperature value that results in i=0 + assert mp.evalf(T, 97) == 3.0 # Should evaluate correctly based on index logic def test_material_property_errors(): """Test error handling in MaterialProperty.""" @@ -64,31 +54,17 @@ def test_material_property_errors(): # Test evaluation with wrong symbol mp = MaterialProperty(X * 100) - with pytest.raises(TypeError, match="Symbol T not found in expression or assignments"): - mp.evalf(T, 100.0) + with pytest.raises(TypeError): + mp.evalf(T, 100.0) # Should raise TypeError because X != T # Test invalid assignments - with pytest.raises(ValueError, match="None assignments are not allowed"): - MaterialProperty(T * 100, assignments=[None]) - -def test_material_property_array_evaluation(): - """Test MaterialProperty evaluation with arrays.""" - T = sp.Symbol('T') - mp = MaterialProperty(T * 100) - - # Test with numpy array - temps = np.array([1.0, 2.0, 3.0]) - result = mp.evalf(T, temps) - assert isinstance(result, np.ndarray) - assert np.allclose(result, temps * 100.0) - - # Test with invalid array values - with pytest.raises(TypeError): - mp.evalf(T, np.array(['a', 'b', 'c'])) + with pytest.raises(ValueError): + MaterialProperty(T * 100, assignments=[None]) # None assignment should raise ValueError def test_material_property_piecewise(): """Test MaterialProperty with piecewise functions.""" T = sp.Symbol('T') + mp = MaterialProperty(sp.Piecewise( (100, T < 0), (200, T >= 100), @@ -99,10 +75,16 @@ def test_material_property_piecewise(): assert mp.evalf(T, 50) == 50 assert mp.evalf(T, 150) == 200 -def test_material_property_numpy_types(): - """Test MaterialProperty with numpy numeric types.""" +def test_material_property_array_evaluation(): + """Test MaterialProperty evaluation with arrays.""" T = sp.Symbol('T') + mp = MaterialProperty(T * 100) - assert mp.evalf(T, np.float32(1.0)) == 100.0 - assert mp.evalf(T, np.float64(1.0)) == 100.0 + # Test with numpy array + temps = np.array([1.0, 2.0, 3.0]) + + result = mp.evalf(T, temps) + + assert isinstance(result, np.ndarray) + assert np.allclose(result, temps * 100.0) diff --git a/tests/tests.py b/tests/tests.py deleted file mode 100644 index 75c5aa3c84d2eb34865ef8618efc658af099fd2a..0000000000000000000000000000000000000000 --- a/tests/tests.py +++ /dev/null @@ -1,326 +0,0 @@ -import pytest -import numpy as np -import sympy as sp -from pystencils.types.quick import Arr - -from src.pymatlib.core.alloy import Alloy -from src.pymatlib.data.alloys.SS316L.SS316L import create_SS316L -from src.pymatlib.core.assignment_converter import type_mapping, assignment_converter -from src.pymatlib.data.element_data import Fe, Cr, Mn, Ni -from src.pymatlib.core.interpolators import interpolate_property, interpolate_lookup, interpolate_equidistant, \ - check_equidistant -from src.pymatlib.core.models import density_by_thermal_expansion, thermal_diffusivity_by_heat_conductivity -from src.pymatlib.core.typedefs import MaterialProperty, Assignment - - -def test_alloy_creation(): - # Test creating an alloy with valid elemental composition and phase transition temperatures - alloy = Alloy(elements=[Fe, Cr, Mn, Ni], composition=[0.7, 0.2, 0.05, 0.05], temperature_solidus=1700, temperature_liquidus=1800) - assert np.allclose(alloy.composition, [0.7, 0.2, 0.05, 0.05]) - assert alloy.temperature_solidus == 1700. - assert alloy.temperature_liquidus == 1800. - - # Test creating an alloy with invalid elemental composition - with pytest.raises(ValueError): - Alloy(elements=[Fe, Cr], composition=[0.6, 0.5], temperature_solidus=1700., temperature_liquidus=1800.) - - # Test creating an alloy with invalid phase transition temperatures - with pytest.raises(ValueError): - Alloy(elements=[Fe, Cr, Mn, Ni], composition=[0.7, 0.2, 0.05, 0.05], temperature_solidus=1900., temperature_liquidus=1800.) - -def test_create_SS316L(): - # Test creating SS316L alloy with a float temperature input - alloy = create_SS316L(1400.0) - assert isinstance(alloy.density, MaterialProperty) - assert isinstance(alloy.heat_capacity, MaterialProperty) - assert isinstance(alloy.heat_conductivity, MaterialProperty) - assert isinstance(alloy.thermal_diffusivity, MaterialProperty) - - # Test creating SS316L alloy with a symbolic temperature input - T = sp.Symbol('T') - alloy = create_SS316L(T) - assert isinstance(alloy.density, MaterialProperty) - assert isinstance(alloy.heat_capacity, MaterialProperty) - assert isinstance(alloy.heat_conductivity, MaterialProperty) - assert isinstance(alloy.thermal_diffusivity, MaterialProperty) - - # Test creating SS316L alloy with different combinations of property calculation methods - alloy = create_SS316L(1400.0) - alloy.density = alloy.density.expr - alloy.heat_capacity = alloy.heat_capacity.evalf(T, 1400.0) - assert isinstance(alloy.density, sp.Expr) - assert isinstance(alloy.heat_capacity, float) - -def test_interpolate_property(): - # Test interpolating properties with float temperature inputs - T_symbol = sp.Symbol('T') # Define a symbolic variable - T_value = 1400.0 - temp_array = np.array([1300.0, 1400.0, 1500.0]) - prop_array = np.array([100.0, 200.0, 300.0]) - result = interpolate_property(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test interpolating properties with symbolic temperature inputs - result = interpolate_property(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test interpolating properties with different combinations of temperature and property arrays - temp_array = [1300.0, 1400.0, 1500.0] - prop_array = [100.0, 200.0, 300.0] - result = interpolate_property(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - temp_array = tuple([1300.0, 1400.0, 1500.0]) - prop_array = tuple([100.0, 200.0, 300.0]) - result = interpolate_property(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test with ascending and descending order arrays - temp_array_asc = np.array([1300.0, 1400.0, 1500.0]) - prop_array_asc = np.array([100.0, 200.0, 300.0]) - result_asc = interpolate_property(T_symbol, temp_array_asc, prop_array_asc) - assert isinstance(result_asc, MaterialProperty) - assert np.isclose(result_asc.evalf(T_symbol, T_value), 200.0) - - temp_array_desc = np.array([1500.0, 1400.0, 1300.0]) - prop_array_desc = np.array([300.0, 200.0, 100.0]) - result_desc = interpolate_property(T_symbol, temp_array_desc, prop_array_desc) - assert isinstance(result_desc, MaterialProperty) - assert np.isclose(result_desc.evalf(T_symbol, T_value), 200.0) - - # Test with different temp_array_limit values - result_limit_6 = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, temp_array_limit=6) - assert isinstance(result_limit_6, MaterialProperty) - assert np.isclose(result_limit_6.evalf(T_symbol, T_value), 200.0) - - result_limit_3 = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, temp_array_limit=3) - assert isinstance(result_limit_3, MaterialProperty) - assert np.isclose(result_limit_3.evalf(T_symbol, T_value), 200.0) - - # Test with force_lookup True and False - result_force_lookup_true = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, force_lookup=True) - assert isinstance(result_force_lookup_true, MaterialProperty) - assert np.isclose(result_force_lookup_true.evalf(T_symbol, T_value), 200.0) - - result_force_lookup_false = interpolate_property(T_symbol, temp_array_asc, prop_array_asc, force_lookup=False) - assert isinstance(result_force_lookup_false, MaterialProperty) - assert np.isclose(result_force_lookup_false.evalf(T_symbol, T_value), 200.0) - -def test_interpolate_lookup(): - # Define a symbolic variable - T_symbol = sp.Symbol('T') - - # Test lookup interpolation with float temperature inputs - T_value = 1400.0 - temp_array = np.array([1300.0, 1400.0, 1500.0]) - prop_array = np.array([100.0, 200.0, 300.0]) - result = interpolate_lookup(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test lookup interpolation with symbolic temperature inputs - result = interpolate_lookup(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test with different combinations of temperature and property arrays - temp_array = [1300.0, 1400.0, 1500.0] - prop_array = [100.0, 200.0, 300.0] - result = interpolate_lookup(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - temp_array = tuple([1300.0, 1400.0, 1500.0]) - prop_array = tuple([100.0, 200.0, 300.0]) - result = interpolate_lookup(T_symbol, temp_array, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test with ascending and descending order arrays - temp_array_asc = np.array([1300.0, 1400.0, 1500.0]) - prop_array_asc = np.array([100.0, 200.0, 300.0]) - result_asc = interpolate_lookup(T_symbol, temp_array_asc, prop_array_asc) - assert isinstance(result_asc, MaterialProperty) - assert np.isclose(result_asc.evalf(T_symbol, T_value), 200.0) - - temp_array_desc = np.array([1500.0, 1400.0, 1300.0]) - prop_array_desc = np.array([300.0, 200.0, 100.0]) - result_desc = interpolate_lookup(T_symbol, temp_array_desc, prop_array_desc) - assert isinstance(result_desc, MaterialProperty) - assert np.isclose(result_desc.evalf(T_symbol, T_value), 200.0) - -def test_interpolate_equidistant(): - # Define a symbolic variable - T_symbol = sp.Symbol('T') - - # Test equidistant interpolation with float temperature inputs - T_value = 1400.0 - temp_base = 1300.0 - temp_incr = 100.0 - prop_array = np.array([100.0, 200.0, 300.0]) - result = interpolate_equidistant(T_value, temp_base, temp_incr, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test equidistant interpolation with symbolic temperature inputs - result = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test with different combinations of temperature and property arrays - temp_base = 1300.0 - temp_incr = 100.0 - prop_array = [100.0, 200.0, 300.0] - result = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - temp_base = 1300.0 - temp_incr = 100.0 - prop_array = tuple([100.0, 200.0, 300.0]) - result = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array) - assert isinstance(result, MaterialProperty) - assert np.isclose(result.evalf(T_symbol, T_value), 200.0) - - # Test with ascending and descending order arrays - temp_base = 1300.0 - temp_incr = 100.0 - prop_array_asc = np.array([100.0, 200.0, 300.0]) - result_asc = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array_asc) - assert isinstance(result_asc, MaterialProperty) - assert np.isclose(result_asc.evalf(T_symbol, T_value), 200.0) - - temp_base = 1300.0 - temp_incr = 100.0 - prop_array_desc = np.array([300.0, 200.0, 100.0]) - result_desc = interpolate_equidistant(T_symbol, temp_base, temp_incr, prop_array_desc) - assert isinstance(result_desc, MaterialProperty) - assert np.isclose(result_desc.evalf(T_symbol, T_value), 200.0) - -# Define the temp fixture -@pytest.fixture -def temp(): - return np.array([100.0, 200.0, 300.0, 400.0, 500.0]) - -def test_test_equidistant(temp): - # Test with equidistant temperature array - assert check_equidistant(temp) == 100.0 - - # Test with non-equidistant temperature array - temp_non_equidistant = np.array([100.0, 150.0, 300.0, 450.0, 500.0]) - assert check_equidistant(temp_non_equidistant) == 0.0 - -def test_density_by_thermal_expansion(): - # Test calculating density with float temperature and thermal expansion coefficient inputs - T = 1400.0 - T_ref = 1000.0 - rho_ref = 8000.0 - alpha = 1e-5 - result = density_by_thermal_expansion(T, T_ref, rho_ref, alpha) - assert np.isclose(result, 7904.76) - - # Test calculating density with symbolic temperature and thermal expansion coefficient inputs - T = sp.Symbol('T') - result = density_by_thermal_expansion(T, T_ref, rho_ref, alpha) - assert isinstance(result, sp.Expr) - assert np.isclose(result.subs(T, 1400.0), 7904.76) - - # Test calculating density with numpy array temperature and thermal expansion coefficient inputs - T = np.array([1300.0, 1400.0, 1500.0]) - result = density_by_thermal_expansion(T, T_ref, rho_ref, alpha) - assert isinstance(result, np.ndarray) - assert np.allclose(result, [7928.43, 7904.76, 7881.19]) - -def test_thermal_diffusivity_by_heat_conductivity(): - # Test calculating thermal diffusivity with float heat conductivity, density, and heat capacity inputs - k = 50.0 - rho = 8000.0 - c_p = 500.0 - result = thermal_diffusivity_by_heat_conductivity(k, rho, c_p) - assert np.isclose(result, 1.25e-5) - - # Test calculating thermal diffusivity with symbolic heat conductivity, density, and heat capacity inputs - k = sp.Symbol('k') - rho = sp.Symbol('rho') - c_p = sp.Symbol('c_p') - result = thermal_diffusivity_by_heat_conductivity(k, rho, c_p) - assert isinstance(result, sp.Expr) - assert result == k / (rho * c_p) - - # Test calculating thermal diffusivity with numpy array heat conductivity, density, and heat capacity inputs - k = np.array([50.0, 60.0, 70.0]) - rho = np.array([8000.0, 8100.0, 8200.0]) - c_p = np.array([500.0, 510.0, 520.0]) - result = thermal_diffusivity_by_heat_conductivity(k, rho, c_p) - assert isinstance(result, np.ndarray) - assert np.allclose(result, [1.25e-5, 1.45243282e-5, 1.64165103e-5]) - -def test_alloy_single_element(): - # Test creating an alloy with a single element - alloy = Alloy(elements=[Fe], composition=[1.0], temperature_solidus=1800, temperature_liquidus=1900) - assert len(alloy.elements) == 1 - assert alloy.composition == [1.0] - -def test_alloy_property_modification(): - # Test accessing and modifying individual alloy properties - alloy = create_SS316L(1400.0) - assert isinstance(alloy.density, MaterialProperty) - # Set the density to a MaterialProperty instance with a constant expression - alloy.density = MaterialProperty(expr=sp.Float(8000.0)) - assert alloy.density.expr == sp.Float(8000.0) - -def test_create_SS316L_invalid_temperature(): - # Test creating SS316L alloy with invalid temperature inputs - with pytest.raises(ValueError): - create_SS316L(-100.0) # Negative temperature - with pytest.raises(ValueError): - create_SS316L(3500.0) # Temperature outside valid range - -def test_density_by_thermal_expansion_invalid_inputs(): - # Test calculating density with invalid temperature or thermal expansion coefficient inputs - with pytest.raises(ValueError): - density_by_thermal_expansion(-100.0, 1000.0, 8000.0, 1e-5) - with pytest.raises(ValueError): - density_by_thermal_expansion(1000.0, -1000.0, 8000.0, 1e-5) - with pytest.raises(ValueError): - density_by_thermal_expansion(1000.0, 1000.0, -8000.0, 1e-5) - with pytest.raises(ValueError): - density_by_thermal_expansion(1000.0, 1000.0, 8000.0, -1e-5) - with pytest.raises(ValueError): - density_by_thermal_expansion(np.array([-100.0, 1000.0]), 1000.0, 8000.0, 1e-5) - -def test_thermal_diffusivity_invalid_inputs(): - # Test calculating thermal diffusivity with invalid heat conductivity, density, or heat capacity inputs - with pytest.raises(ValueError): - thermal_diffusivity_by_heat_conductivity(-10.0, 8000.0, 500.0) # Negative heat conductivity - with pytest.raises(ValueError): - thermal_diffusivity_by_heat_conductivity(50.0, -8000.0, 500.0) # Negative density - with pytest.raises(ValueError): - thermal_diffusivity_by_heat_conductivity(50.0, 8000.0, -500.0) # Negative heat capacity - -def test_type_mapping_unsupported(): - # Test mapping unsupported type strings - with pytest.raises(ValueError): - type_mapping("unsupported_type", 1) - -# Additional test cases -def test_type_mapping(): - assert isinstance(type_mapping("double[]", 5), Arr) - assert isinstance(type_mapping("float[]", 3), Arr) - assert type_mapping("double", 1) == np.dtype('float64') - assert type_mapping("float", 1) == np.dtype('float32') - assert type_mapping("int", 1) == np.dtype('int32') - assert type_mapping("bool", 1) == np.dtype('bool') - - with pytest.raises(ValueError): - type_mapping("unsupported_type", 1) - -def test_assignment_converter_invalid(): - # Test converting assignments with invalid or missing attributes - invalid_assignment = Assignment(lhs=None, rhs=None, lhs_type=None) - with pytest.raises(ValueError, match="Invalid assignment: lhs, rhs, and lhs_type must not be None"): - assignment_converter([invalid_assignment])