diff --git a/apps/tutorials/codegen/HeatEquationKernel.py b/apps/tutorials/codegen/HeatEquationKernel.py index 9c418fc977b34f24344619c04e40d565a2210980..a9c5e472ea25da75888b4bfa038ec175ffba6983 100644 --- a/apps/tutorials/codegen/HeatEquationKernel.py +++ b/apps/tutorials/codegen/HeatEquationKernel.py @@ -1,252 +1,11 @@ import sys sys.path.append('/local/ca00xebo/repos/walberla') -import numpy as np import sympy as sp import pystencils as ps from pystencils_walberla import CodeGeneration, generate_sweep -from dataclasses import dataclass -from pystencils.typing import PointerType -import src.materials.alloys.Ti6Al4V as ti -from src.materials.get_parameters import get_parameters -from src.materials.alloys.Ti6Al4V import Ti6Al4V_parameters - -''' -def interpolate(x, xmin, xmax, ymin, ymax): - """ - Linear interpolation between two points: y = y_1 + ((y2 - y1) / (x2 - x1)) * (x - x1) - """ - return (ymin * (xmax - x) + ymax * (x - xmin)) / (xmax - xmin) - - -def interpolate_property(T, base_temperature, base_values): # 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 base_temperature and base_values are lists or arrays - if not isinstance(base_temperature, (list, np.ndarray)) or not isinstance(base_values, (list, np.ndarray)): - raise TypeError("base_temperature and base_values must be of type list or np.ndarray") - # Convert to lists if they are numpy arrays - if isinstance(base_temperature, np.ndarray): - base_temperature = base_temperature.tolist() - if isinstance(base_values, np.ndarray): - base_values = base_values.tolist() - # 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" - - if isinstance(T, sp.Expr): # Symbolic expression - base_temperature = [sp.Float(t) for t in base_temperature] - base_values = [sp.Float(val) for val in base_values] - 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])) - conditions.append((interp_expr, sp.And(T >= base_temperature[i], T < base_temperature[i + 1]))) - return sp.Piecewise(*conditions) - else: # Numeric expression - return np.interp(T, base_temperature, base_values) - - -def density_by_thermal_expansion(T, base_temperature, base_density, thermal_expansion_coefficient): - """ - Calculate density based on thermal expansion: rho_0 / (1 + tec * (T - T_0)) - - :param T: Temperature value. - :param base_temperature: Reference temperature. - :param base_density: Density at reference temperature. - :param thermal_expansion_coefficient: Thermal expansion coefficient. - """ - return base_density / (1 + thermal_expansion_coefficient * (T - base_temperature)) ** 3 - - -def thermal_diffusivity_func(heat_conductivity, density, specific_heat_capacity): - """ - Calculate thermal diffusivity: k(T) / (rho(T) * c_p(T)) - - :param heat_conductivity: Thermal conductivity. - :param density: Density. - :param specific_heat_capacity: Specific heat capacity. - """ - return heat_conductivity / (density * specific_heat_capacity) - - -def density_lookup(T, temperature_array, density_array): - """ - Look up density based on temperature using interpolation. - - :param T: Temperature value. - :param temperature_array: Array of temperatures. - :param density_array: Array of densities. - """ - if isinstance(T, sp.Expr): # Symbolic expression - conditions = [ - (density_array[0], T < temperature_array[0]), - (density_array[-1], T >= temperature_array[-1]) - ] - for i in range(len(temperature_array) - 1): - interp_expr = (density_array[i] + - (density_array[i+1] - density_array[i]) / (temperature_array[i+1] - temperature_array[i]) * - (T - temperature_array[i])) - conditions.append((interp_expr, sp.And(T >= temperature_array[i], T < temperature_array[i + 1]))) - return sp.Piecewise(*conditions) - else: # Numeric expression - return np.interp(T, temperature_array, density_array) - - -def get_arguments(T, temperatures, args): - """ - Recursively get arguments for parameter functions. - - :param T: Temperature value. - :param temperatures: Solidus and liquidus temperatures. - :param args: Arguments to be processed. - """ - converted_args = [] - for arg in args: - if isinstance(arg, (Solidus_Liquidus_Parameter, Functional_Parameter)): - converted_args.append(get_parameters(T, temperatures, arg)) - else: - converted_args.append(arg) - return converted_args - - -def get_parameters(T, temperatures, parameter): - """ - Resolve parameters based on temperature and parameter type. - - :param T: Temperature value. - :param temperatures: Solidus and liquidus temperatures. - :param parameter: Parameter to be resolved. - """ - if isinstance(parameter, Solidus_Liquidus_Parameter): - return sp.Piecewise( - (parameter.sol, T <= temperatures.sol), - (parameter.liq, T >= temperatures.liq), - (interpolate(T, temperatures.sol, temperatures.liq, parameter.sol, parameter.liq), True) - ) - elif isinstance(parameter, Functional_Parameter): - resolved_args = [get_parameters(T, temperatures, arg) for arg in parameter.args] - if parameter.func == 'thermal_expansion': - return density_by_thermal_expansion(T, *resolved_args) # *get_parameters(T, temperatures, parameter.args) - elif parameter.func == 'interpolation': - return interpolate_property(T, *resolved_args) - elif parameter.func == 'interpolation_in_array': # TODO - T_base, T_incr, data_array, data_symbol = resolved_args - idx = sp.floor((T - T_base) / T_incr) - mod = (T - T_base) - idx * T_incr # mod replaces (T - T_base) % T_incr - return 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) - ) - elif parameter.func == 'lookup': - return density_lookup(T, *resolved_args) - elif parameter.func == 'thermal_diffusivity': - return thermal_diffusivity_func(*resolved_args) - else: - raise ValueError("No known format in the dict: parameter = ", parameter) - else: - return parameter # assume everything which is not a dict is a float, int, etc. - - -# Material Data Class -@dataclass -class Ti6Al4V: # 90% Ti, 6% Al, 4% V - latent_heat = 290000 # m²/s² - temperature_solidus_1 = 1876.0 # k Ref [1] - temperature_solidus_2 = 1880.0 # k Ref [2] - temperature_liquidus = 1928.0 # k Ref [2] - density_room = 4430.0 # kg/m³ Ref [5] - thermal_expansion_coefficient = 10e-6 # /k Ref[6] - heat_capacity_solidus = 700.0 # J/kg-k - heat_capacity_liquidus = 1126.0 # J/kg-k - heat_conductivity_solidus = 21.58 # W/m-k - heat_conductivity_liquidus = 33.60 # W/m-k - density_temp_array = [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0] - density_data_array = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0] - density_temp_base = 1878.0 - density_temp_incr = 8.0 - # thermal_diffusivity_solidus = 727.7 - # thermal_diffusivity_liquidus = 708.6 - # electrical_resistivity = [1, 2, 5, 10, 20, 50, 100] - # electrical_resistivity_temperatures = [800, 900, 1200, 1500, 1700, 1900, 2000] - # Define temperature and density arrays - density_temp_array_lookup = np.array([1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0]) - density_data_array_lookup = np.array([4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0]) - - -@dataclass -class Constants: - temperature_room = 298.15 # k - N_a = 6.022141e23 # /mol - u = 1.660538e-27 # kg - - -# Instantiate the Ti6Al4V class -ti6al4v = Ti6Al4V() - -Ti6Al4V_latent_heat = ti6al4v.latent_heat -Ti6Al4V_thermal_expansion_coefficient = ti6al4v.thermal_expansion_coefficient - - -@dataclass -class Solidus_Liquidus_Parameter: - sol: float - liq: float - - -@dataclass -class Functional_Parameter: - func: str - args: list - - -# Parameters for Ti6Al4V -Ti6Al4V_temperatures = Solidus_Liquidus_Parameter( - sol=0.5 * (ti6al4v.temperature_solidus_1 + ti6al4v.temperature_solidus_2), - liq=ti6al4v.temperature_liquidus) - -Ti6Al4V_heat_conductivity = Solidus_Liquidus_Parameter( - sol=ti6al4v.heat_conductivity_solidus, - liq=ti6al4v.heat_conductivity_liquidus) - -Ti6Al4V_specific_heat_capacity = Solidus_Liquidus_Parameter( - sol=ti6al4v.heat_capacity_solidus, - liq=ti6al4v.heat_capacity_liquidus) - -Ti6Al4V_density_tec = Functional_Parameter( - func='thermal_expansion', - args=[Constants.temperature_room, ti6al4v.density_room, ti6al4v.thermal_expansion_coefficient]) - -Ti6Al4V_density_int = Functional_Parameter( - func='interpolation', - args=[ti6al4v.density_temp_array, ti6al4v.density_data_array]) - -Ti6Al4V_density_in_array = Functional_Parameter( - func='interpolation_in_array', # TODO - args=[ti6al4v.density_temp_base, ti6al4v.density_temp_incr, ti6al4v.density_data_array, - sp.IndexedBase(ps.TypedSymbol('density_data_symbol', PointerType(sp.Basic('float32'))), # PointerType(create_type(np.float32)) PointerType(base_type=float32) PointerType(sp.Basic('float32')) - shape=len(ti6al4v.density_data_array))]) - -Ti6Al4V_density_lookup = Functional_Parameter( - func='lookup', - args=[ti6al4v.density_temp_array_lookup, ti6al4v.density_data_array_lookup]) - -Ti6Al4V_thermal_diffusivity = Functional_Parameter( - func='thermal_diffusivity', - args=[Ti6Al4V_heat_conductivity, Ti6Al4V_density_lookup, Ti6Al4V_specific_heat_capacity] - # solidus=ti6al4v.thermal_diffusivity_solidus, - # liquidus=ti6al4v.thermal_diffusivity_liquidus -) -''' +from src.materials.alloys import Ti6Al4V +from src.materials.models import thermal_diffusivity_by_heat_conductivity +from pystencils.types.quick import * with CodeGeneration() as ctx: data_type = "float64" if ctx.double_accuracy else "float32" @@ -260,18 +19,25 @@ with CodeGeneration() as ctx: discretize = ps.fd.Discretization2ndOrder(dx=dx, dt=dt) heat_pde_discretized = discretize(heat_pde) heat_pde_discretized = heat_pde_discretized.args[1] + heat_pde_discretized.args[0].simplify() - - thermal_diffusivity_expr = get_parameters(u.center(), Ti6Al4V_parameters.Ti6Al4V_temperatures, Ti6Al4V_parameters.Ti6Al4V_thermal_diffusivity) - + Ti6Al4V = Ti6Al4V.create_Ti6Al4V(u.center()) + # density, density_subexpr = Ti6Al4V.density # Alternative + subexp = [] + for a in Ti6Al4V.assignments: + data_symbol = ps.TypedSymbol(a[0].label.name, Arr(Fp(64))) # Alternative + subexp.append(ps.Assignment(data_symbol, a[1])) + # 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 + subexp.append(ps.Assignment(thermal_diffusivity, thermal_diffusivity_expr)) ac = ps.AssignmentCollection( - subexpressions=[ - ps.Assignment(thermal_diffusivity, thermal_diffusivity_expr) - ], + subexpressions=subexp, main_assignments=[ ps.Assignment(u_tmp.center(), heat_pde_discretized), ps.Assignment(thermal_diffusivity_out.center(), thermal_diffusivity) ]) - ac = ps.simp.simplifications.add_subexpressions_for_divisions(ac) + + # ac = ac.new_with_substitutions(subexp) + + # ac = ps.simp.simplifications.add_subexpressions_for_divisions(ac) # ac = ps.simp.simplifications.add_subexpressions_for_field_reads(ac) # ac = ps.simp.sympy_cse(ac) diff --git a/src/materials/alloys/Alloy.py b/src/materials/alloys/Alloy.py new file mode 100644 index 0000000000000000000000000000000000000000..27975f52fa1063e0a118b7c2a5990a57f5ae8d99 --- /dev/null +++ b/src/materials/alloys/Alloy.py @@ -0,0 +1,54 @@ +import numpy as np +from sympy import Expr +from typing import List, Union +from dataclasses import dataclass, field, asdict +from src.materials.elements import Element +from src.materials.elements import Ti, Al, V + + +# Alloy Base Class +@dataclass +class Alloy: + elements: List[Element] + composition: List[float] + + atomic_number: float = field(init=False) + atomic_mass: float = field(init=False) + temperature_boil: float = field(init=False) + + 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 + + assignments: list[tuple, ...] = field(default_factory=list, 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 __post_init__(self): + self.atomic_number = self.interpolate("atomic_number") + self.atomic_mass = self.interpolate("atomic_mass") + self.temperature_boil = self.interpolate("temperature_boil") + + def solidification_interval(self) -> [float, float]: + return [self.temperature_solidus, self.temperature_liquidus] + + +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(Ti64.heat_conductivity) + Ti64.heat_conductivity = 34 + print(Ti64.heat_conductivity) + print(Ti64.temperature_boil) + Ti64.temperature_boil = 1000 + print(Ti64.temperature_boil) diff --git a/src/materials/alloys/Ti6Al4V.py b/src/materials/alloys/Ti6Al4V.py new file mode 100644 index 0000000000000000000000000000000000000000..4b8ccd2ccfda5d31aecab5f6f8afd46deabb441d --- /dev/null +++ b/src/materials/alloys/Ti6Al4V.py @@ -0,0 +1,65 @@ +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 + + +def create_Ti6Al4V(T: Union[float, sp.Symbol]) -> Alloy: + # 90% Ti, 6% Al, 4% V + Ti6Al4V = Alloy( + [Ti, Al, V], + [0.90, 0.06, 0.04], + 1878.0, + 1928.0 + ) + + 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] + + '''Ti6Al4V.heat_capacity = interpolators.interpolate_lookup( + T, Ti6Al4V.solidification_interval(), [700.0, 1126.0]) # J/kg-k''' + + heat_capacity = interpolators.interpolate_equidistant( + T, 1820, 20, [700, 800, 900, 1000, 1100, 1200], 'heat_capacity') # J/kg-k + + Ti6Al4V.heat_capacity = heat_capacity.expression + Ti6Al4V.assignments += heat_capacity.assignments + + Ti6Al4V.heat_conductivity = interpolators.interpolate_lookup( + T, Ti6Al4V.solidification_interval(), [21.58, 33.60]) # W/m-k + + '''Ti6Al4V.density = models.density_by_thermal_expansion( + T, Constants.temperature_room, 4430, Ti6Al4V.thermal_expansion_coefficient) + + 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])''' + + density = 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.expression + Ti6Al4V.assignments += density.assignments + + Ti6Al4V.thermal_diffusivity = models.thermal_diffusivity_by_heat_conductivity( + Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity) + + return Ti6Al4V + + +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)) diff --git a/src/materials/alloys/Ti6Al4V/Ti6Al4V_parameters.py b/src/materials/alloys/Ti6Al4V/Ti6Al4V_parameters.py deleted file mode 100644 index ff5897e704531a1e1244bd0c9053ccfa27b06100..0000000000000000000000000000000000000000 --- a/src/materials/alloys/Ti6Al4V/Ti6Al4V_parameters.py +++ /dev/null @@ -1,103 +0,0 @@ -import numpy as np -import sympy as sp -import pystencils as ps -from dataclasses import dataclass -from pystencils.typing import PointerType -from src.materials.constants import Constants -from src.materials.dataclasses import Solidus_Liquidus_Parameter, Functional_Parameter - - -# Material Data Class -@dataclass -class Ti6Al4V: # 90% Ti, 6% Al, 4% V - latent_heat = 290000 # m²/s² - temperature_solidus_1 = 1876.0 # k Ref [1] - temperature_solidus_2 = 1880.0 # k Ref [2] - temperature_liquidus = 1928.0 # k Ref [2] - density_room = 4430.0 # kg/m³ Ref [5] - thermal_expansion_coefficient = 10e-6 # /k Ref[6] - heat_capacity_solidus = 700.0 # J/kg-k - heat_capacity_liquidus = 1126.0 # J/kg-k - heat_conductivity_solidus = 21.58 # W/m-k - heat_conductivity_liquidus = 33.60 # W/m-k - density_temp_array = [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0] - density_data_array = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0] - density_temp_base = 1878.0 - density_temp_incr = 8.0 - thermal_diffusivity_solidus = 727.7 - thermal_diffusivity_liquidus = 708.6 - # electrical_resistivity = [1, 2, 5, 10, 20, 50, 100] - # electrical_resistivity_temperatures = [800, 900, 1200, 1500, 1700, 1900, 2000] - # Define temperature and density arrays - density_temp_array_lookup = np.array([1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0]) - density_data_array_lookup = np.array([4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0]) - - -''' -@dataclass -class Constants: - temperature_room = 298.15 # k - N_a = 6.022141e23 # /mol - u = 1.660538e-27 # kg -''' - -# Instantiate the Ti6Al4V class -ti6al4v = Ti6Al4V() - -Ti6Al4V_latent_heat = ti6al4v.latent_heat -Ti6Al4V_thermal_expansion_coefficient = ti6al4v.thermal_expansion_coefficient - -''' -@dataclass -class Solidus_Liquidus_Parameter: - sol: float - liq: float - - -@dataclass -class Functional_Parameter: - func: str - args: list -''' - -# Parameters for Ti6Al4V -Ti6Al4V_temperatures = Solidus_Liquidus_Parameter( - sol=0.5 * (ti6al4v.temperature_solidus_1 + ti6al4v.temperature_solidus_2), - liq=ti6al4v.temperature_liquidus) - -Ti6Al4V_heat_conductivity = Solidus_Liquidus_Parameter( - sol=ti6al4v.heat_conductivity_solidus, - liq=ti6al4v.heat_conductivity_liquidus) - -Ti6Al4V_specific_heat_capacity = Solidus_Liquidus_Parameter( - sol=ti6al4v.heat_capacity_solidus, - liq=ti6al4v.heat_capacity_liquidus) - -Ti6Al4V_density_tec = Functional_Parameter( - func='thermal_expansion', - args=[Constants.temperature_room, ti6al4v.density_room, ti6al4v.thermal_expansion_coefficient]) - -Ti6Al4V_density_int = Functional_Parameter( - func='interpolation', - args=[ti6al4v.density_temp_array, ti6al4v.density_data_array]) - -Ti6Al4V_density_in_array = Functional_Parameter( - func='interpolation_in_array', # TODO - args=[ti6al4v.density_temp_base, ti6al4v.density_temp_incr, ti6al4v.density_data_array, - sp.IndexedBase(ps.TypedSymbol('density_data_symbol', PointerType(sp.Basic('float32'))), - shape=len(ti6al4v.density_data_array))]) -# PointerType(create_type(np.float32)) PointerType(base_type=float32) PointerType(sp.Basic('float32')) - -Ti6Al4V_density_lookup = Functional_Parameter( - func='lookup', - args=[ti6al4v.density_temp_array_lookup, ti6al4v.density_data_array_lookup]) - -Ti6Al4V_thermal_diffusivity1 = Solidus_Liquidus_Parameter( - sol=ti6al4v.thermal_diffusivity_solidus, - liq=ti6al4v.thermal_diffusivity_liquidus -) - -Ti6Al4V_thermal_diffusivity = Functional_Parameter( - func='thermal_diffusivity', - args=[Ti6Al4V_heat_conductivity, Ti6Al4V_density_int, Ti6Al4V_specific_heat_capacity] -) diff --git a/src/materials/alloys/Ti6Al4V/__init__.py b/src/materials/alloys/Ti6Al4V/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/materials/dataclasses.py b/src/materials/dataclasses.py deleted file mode 100644 index a67834b2d70628044a2da0986dbed7731c23b4a2..0000000000000000000000000000000000000000 --- a/src/materials/dataclasses.py +++ /dev/null @@ -1,13 +0,0 @@ -from dataclasses import dataclass - - -@dataclass -class Solidus_Liquidus_Parameter: - sol: float - liq: float - - -@dataclass -class Functional_Parameter: - func: str - args: list diff --git a/src/materials/elements.py b/src/materials/elements.py new file mode 100644 index 0000000000000000000000000000000000000000..049fc1756d98550a2f56042807f88124cc66608b --- /dev/null +++ b/src/materials/elements.py @@ -0,0 +1,43 @@ +from dataclasses import dataclass +from src.materials.constants import Constants + + +# Element Data Class +@dataclass +class Element: + atomic_number: float + atomic_mass: float + temperature_melt: float + temperature_boil: float + latent_heat_of_fusion: float + latent_heat_of_vaporization: float + + +Ti = Element( + atomic_number=22, + atomic_mass=47.867*Constants.u, + temperature_melt=1941, + temperature_boil=3533, + latent_heat_of_fusion=18700, + latent_heat_of_vaporization=427000 +) + + +Al = Element( + atomic_number=13, + atomic_mass=26.9815384*Constants.u, + temperature_melt=933.35, + temperature_boil=2743, + latent_heat_of_fusion=10700, + latent_heat_of_vaporization=284000 +) + + +V = Element( + atomic_number=23, + atomic_mass=50.9415*Constants.u, + temperature_melt=2183, + temperature_boil=3680, + latent_heat_of_fusion=21500, + latent_heat_of_vaporization=444000 +) diff --git a/src/materials/elements/Ti.py b/src/materials/elements/Ti.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/materials/elements/__init__.py b/src/materials/elements/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/materials/get_arguments.py b/src/materials/get_arguments.py deleted file mode 100644 index d6a3bc2e0aca0c3be9ba58ac4b9d87ef2dfcc602..0000000000000000000000000000000000000000 --- a/src/materials/get_arguments.py +++ /dev/null @@ -1,20 +0,0 @@ -# from src.materials.alloys.Ti6Al4V import Ti6Al4V_parameters -from get_parameters import get_parameters -from src.materials.dataclasses import Solidus_Liquidus_Parameter, Functional_Parameter - - -def get_arguments(T, temperatures, args): - """ - Recursively get arguments for parameter functions. - - :param T: Temperature value. - :param temperatures: Solidus and liquidus temperatures. - :param args: Arguments to be processed. - """ - converted_args = [] - for arg in args: - if isinstance(arg, (Solidus_Liquidus_Parameter, Functional_Parameter)): - converted_args.append(get_parameters(T, temperatures, arg)) - else: - converted_args.append(arg) - return converted_args diff --git a/src/materials/get_parameters.py b/src/materials/get_parameters.py deleted file mode 100644 index 311ac0eda1cf9470340166e322c26aa3be0a3868..0000000000000000000000000000000000000000 --- a/src/materials/get_parameters.py +++ /dev/null @@ -1,44 +0,0 @@ -import sympy as sp -from src.materials.interpolators import interpolate, interpolate_property, density_lookup -from src.materials.models import density_by_thermal_expansion, thermal_diffusivity_func -# from src.materials.alloys.Ti6Al4V import Ti6Al4V_parameters -from src.materials.dataclasses import Solidus_Liquidus_Parameter, Functional_Parameter - - -def get_parameters(T, temperatures, parameter): - """ - Resolve parameters based on temperature and parameter type. - - :param T: Temperature value. - :param temperatures: Solidus and liquidus temperatures. - :param parameter: Parameter to be resolved. - """ - if isinstance(parameter, Solidus_Liquidus_Parameter): - return sp.Piecewise( - (parameter.sol, T <= temperatures.sol), - (parameter.liq, T >= temperatures.liq), - (interpolate(T, temperatures.sol, temperatures.liq, parameter.sol, parameter.liq), True) - ) - elif isinstance(parameter, Functional_Parameter): - resolved_args = [get_parameters(T, temperatures, arg) for arg in parameter.args] - if parameter.func == 'thermal_expansion': - return density_by_thermal_expansion(T, *resolved_args) # *get_parameters(T, temperatures, parameter.args) - elif parameter.func == 'interpolation': - return interpolate_property(T, *resolved_args) - elif parameter.func == 'interpolation_in_array': # TODO - T_base, T_incr, data_array, data_symbol = resolved_args - idx = sp.floor((T - T_base) / T_incr) - mod = (T - T_base) - idx * T_incr # mod replaces (T - T_base) % T_incr - return 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) - ) - elif parameter.func == 'lookup': - return density_lookup(T, *resolved_args) - elif parameter.func == 'thermal_diffusivity': - return thermal_diffusivity_func(*resolved_args) - else: - raise ValueError("No known format in the dict: parameter = ", parameter) - else: - return parameter # assume everything which is not a dict is a float, int, etc. diff --git a/src/materials/interpolators.py b/src/materials/interpolators.py index 242254280a2e6bf712862ac077744f67c22fda12..6b32bf27768b537930b26535f92f6c28cb9c5808 100644 --- a/src/materials/interpolators.py +++ b/src/materials/interpolators.py @@ -1,15 +1,59 @@ import numpy as np import sympy as sp +from typing import Union, List +# import pystencils as ps +# from pystencils.types.quick import * +from src.materials.property import Property +from pystencils.sympyextensions import CastFunc -def interpolate(x, xmin, xmax, ymin, ymax): +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, Property]: # TODO """ - Linear interpolation between two points: y = y_1 + ((y2 - y1) / (x2 - x1)) * (x - x1) + 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. """ - return (ymin * (xmax - x) + ymax * (x - xmin)) / (xmax - xmin) - - -def interpolate_property(T, base_temperature, base_values): # TODO + 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 + 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)) + return Property(result, ((data_base, data_array),)) # [result, ps.Assignment(data_symbol, data_array), ps.Assignment(data_symbol, data_array)] # Alternative resurn a property, 1st arg: result, 2nd: List[tuple] + else: + 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. @@ -17,98 +61,65 @@ def interpolate_property(T, base_temperature, base_values): # TODO :param base_temperature: List or array of base temperatures. :param base_values: List or array of property values corresponding to base temperatures. """ - # Ensure base_temperature and base_values are lists or arrays - if not isinstance(base_temperature, (list, np.ndarray)) or not isinstance(base_values, (list, np.ndarray)): - raise TypeError("base_temperature and base_values must be of type list or np.ndarray") - # Convert to lists if they are numpy arrays - if isinstance(base_temperature, np.ndarray): - base_temperature = base_temperature.tolist() - if isinstance(base_values, np.ndarray): - base_values = base_values.tolist() - - # Debugging: Print lengths and types - # print(f"Length of base_temperature: {len(base_temperature)}") - # print(f"Length of base_values: {len(base_values)}") - # print(f"Type of base_temperature: {type(base_temperature)}") - # print(f"Type of base_values: {type(base_values)}") + # 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" - if isinstance(T, sp.Expr): # Symbolic expression - base_temperature = [sp.Float(t) for t in base_temperature] - base_values = [sp.Float(val) for val in base_values] + 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] 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]) * + (base_values[i + 1] - base_values[i]) / (base_temperature[i + 1] - base_temperature[i]) * (T - base_temperature[i])) - conditions.append((interp_expr, sp.And(T >= base_temperature[i], T < base_temperature[i + 1]))) + 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) 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) -# Example usage: -Temp = sp.Symbol('T') -density_temp_array1 = [200.0, 300.0, 400.0, 500.0, 600.0] -density_data_array1 = [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] +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_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] -# Symbolic interpolation -symbolic_result = interpolate_property(Temp, density_temp_array2, density_data_array2) -print("Symbolic interpolation result:", symbolic_result) + # Symbolic interpolation + symbolic_result = interpolate_lookup(Temp, density_temp_array1, density_data_array1) + print("Symbolic interpolation result with interpolate_lookup:", symbolic_result) -# Numeric interpolation -numeric_result = interpolate_property(450.0, density_temp_array2, density_data_array2) -print("Numeric interpolation result:", numeric_result) + # Numeric interpolation + numeric_result = interpolate_lookup(450.0, density_temp_array1, density_data_array1) + print("Numeric interpolation result with interpolate_lookup:", numeric_result) + T_base = 200 + T_incr = 100 -def density_lookup(T, temperature_array, density_array): - """ - Look up density based on temperature using interpolation. + # Symbolic interpolation + symbolic_result = interpolate_equidistant(Temp, T_base, T_incr, density_data_array1, 'density') + print("Symbolic interpolation result with interpolate_equidistant:", symbolic_result) - :param T: Temperature value. - :param temperature_array: Array of temperatures. - :param density_array: Array of densities. - """ - if len(temperature_array) != len(density_array): - raise ValueError("temperature_array and density_array must have the same length") - if isinstance(T, sp.Expr): # Symbolic expression - conditions = [ - (density_array[0], T < temperature_array[0]), - (density_array[-1], T >= temperature_array[-1]) - ] - for i in range(len(temperature_array) - 1): - interp_expr = (density_array[i] + - (density_array[i+1] - density_array[i]) / (temperature_array[i+1] - temperature_array[i]) * - (T - temperature_array[i])) - conditions.append((interp_expr, sp.And(T >= temperature_array[i], T < temperature_array[i + 1]))) - return sp.Piecewise(*conditions) - else: # Numeric expression - return np.interp(T, temperature_array, density_array) - - -# Example usage: -Temp = sp.Symbol('T') -density_temp_array3 = [200.0, 300.0, 400.0, 500.0, 600.0] -density_data_array3 = [50.0, 40.0, 30.0, 20.0, 10.0] -density_temp_array4 = np.array([200.0, 300.0, 400.0, 500.0, 600.0]) -density_data_array4 = np.array([50.0, 40.0, 30.0, 20.0, 10.0]) -density_temp_array5 = [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0] -density_data_array5 = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0] -density_temp_array6 = np.array([1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0]) -density_data_array6 = np.array([4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0]) - -# Symbolic interpolation -symbolic_result = density_lookup(Temp, density_temp_array4, density_data_array4) -print("Symbolic interpolation result:", symbolic_result) - -# Numeric interpolation -numeric_result = density_lookup(450.0, density_temp_array4, density_data_array4) -print("Numeric interpolation result:", numeric_result) + # Numeric interpolation + numeric_result = interpolate_equidistant(450.0, T_base, T_incr, density_data_array1, 'density') + print("Numeric interpolation result with interpolate_equidistant:", numeric_result) diff --git a/src/materials/models.py b/src/materials/models.py index cd098fec05fdc4899f95e48450874ce3386d1a8f..a4a7372eae51d65e9d8454623148c032d962f480 100644 --- a/src/materials/models.py +++ b/src/materials/models.py @@ -1,4 +1,13 @@ -def density_by_thermal_expansion(T, base_temperature, base_density, thermal_expansion_coefficient): +from sympy import Expr, Symbol, simplify +from typing import Union + + +def density_by_thermal_expansion( + T: Union[float, Symbol], + base_temperature: float, + base_density: float, + thermal_expansion_coefficient: Union[float, Expr]) \ + -> Union[float, Expr]: """ Calculate density based on thermal expansion: rho_0 / (1 + tec * (T - T_0)) @@ -10,12 +19,19 @@ def density_by_thermal_expansion(T, base_temperature, base_density, thermal_expa return base_density / (1 + thermal_expansion_coefficient * (T - base_temperature)) ** 3 -def thermal_diffusivity_func(heat_conductivity, density, specific_heat_capacity): +def thermal_diffusivity_by_heat_conductivity( + heat_conductivity: Union[float, Expr], + density: Union[float, Expr], + heat_capacity: Union[float, Expr]) \ + -> Union[float, Expr]: """ Calculate thermal diffusivity: k(T) / (rho(T) * c_p(T)) :param heat_conductivity: Thermal conductivity. :param density: Density. - :param specific_heat_capacity: Specific heat capacity. + :param heat_capacity: Specific heat capacity. """ - return heat_conductivity / (density * 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) + return result diff --git a/src/materials/property.py b/src/materials/property.py new file mode 100644 index 0000000000000000000000000000000000000000..aacd51db2d94a68084ecae3a8545c36a2ff1b6a4 --- /dev/null +++ b/src/materials/property.py @@ -0,0 +1,8 @@ +from sympy import Expr +from dataclasses import dataclass + + +@dataclass +class Property: + expression: Expr | float + assignments: tuple[tuple, ...] = tuple