diff --git a/apps/tutorials/codegen/01_CodegenHeatEquation.cpp b/apps/tutorials/codegen/01_CodegenHeatEquation.cpp index 8f425ca008f8b4609977b50573943ef5d2c53d56..5c01652116a6fd3b58b81c60270a267139293a3e 100644 --- a/apps/tutorials/codegen/01_CodegenHeatEquation.cpp +++ b/apps/tutorials/codegen/01_CodegenHeatEquation.cpp @@ -158,12 +158,24 @@ int main(int argc, char** argv) << AfterFunction([blocks, uFieldId, uTmpFieldId]() { swapFields(*blocks, uFieldId, uTmpFieldId); }, "Swap"); - auto vtkWriter = field::createVTKOutput< ScalarField, float >( uFieldId, *blocks, "temperature", uint_c(200), uint_c(0) ); + auto vtkOutput = vtk::createVTKOutput_BlockData(*blocks, "vtk", 200, 0, false, "vtk_out", + "simulation_step", false, true, true, false, 0); + + auto tempWriter = + make_shared< field::VTKWriter< ScalarField > >(uFieldId, "temperature"); + vtkOutput->addCellDataWriter(tempWriter); + + auto kappaWriter = + make_shared< field::VTKWriter< ScalarField > >(kappa_outFieldId, "kappa"); + vtkOutput->addCellDataWriter(kappaWriter); + + /*auto vtkWriter = field::createVTKOutput< ScalarField, float >( uFieldId, *blocks, "temperature", uint_c(200), uint_c(0) ); vtkWriter(); timeloop.addFuncAfterTimeStep(vtkWriter, "VTK"); auto vtkWriter1 = field::createVTKOutput< ScalarField, float >( kappa_outFieldId, *blocks, "kappa", uint_c(200), uint_c(0) ); - vtkWriter1(); - timeloop.addFuncAfterTimeStep(vtkWriter1, "VTK1"); + vtkWriter1();*/ + + timeloop.addFuncAfterTimeStep(vtk::writeFiles(vtkOutput), "VTK Output"); timeloop.run(); diff --git a/apps/tutorials/codegen/HeatEquationKernel.py b/apps/tutorials/codegen/HeatEquationKernel.py index 9ca54bcf9a7d2dcb6809ae92f6c7743c435f4182..29e27b01c10f51a353f76e63bc6d46e13e40fe57 100644 --- a/apps/tutorials/codegen/HeatEquationKernel.py +++ b/apps/tutorials/codegen/HeatEquationKernel.py @@ -5,10 +5,8 @@ import pystencils as ps from pystencils_walberla import CodeGeneration, generate_sweep from src.materials.alloys import Ti6Al4V from src.materials.models import thermal_diffusivity_by_heat_conductivity -from pystencils.types.quick import * -from pystencils.sympyextensions.typed_sympy import DynamicType, CastFunc -from src.materials.typedefs import type_mapping from src.materials.assignment_converter import assignment_converter + with CodeGeneration() as ctx: data_type = "float64" if ctx.double_accuracy else "float32" @@ -23,10 +21,16 @@ with CodeGeneration() as ctx: heat_pde_discretized = discretize(heat_pde) heat_pde_discretized = heat_pde_discretized.args[1] + heat_pde_discretized.args[0].simplify() Ti6Al4V = Ti6Al4V.create_Ti6Al4V(u.center()) + + # Convert assignments to pystencils format subexp, subs = assignment_converter(Ti6Al4V.assignments.items()) - thermal_diffusivity_expr = thermal_diffusivity_by_heat_conductivity(Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity) - subexp.append(ps.Assignment(thermal_diffusivity, thermal_diffusivity_expr)) + if Ti6Al4V.thermal_diffusivity is not None: + subexp.append(ps.Assignment(thermal_diffusivity, Ti6Al4V.thermal_diffusivity)) + else: + thermal_diffusivity_expr = thermal_diffusivity_by_heat_conductivity(Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity) + subexp.append(ps.Assignment(thermal_diffusivity, thermal_diffusivity_expr)) + ac = ps.AssignmentCollection( subexpressions=subexp, main_assignments=[ diff --git a/src/materials/alloys/Alloy.py b/src/materials/alloys/Alloy.py index 14940d9a8de0b6039da5c466f0b128042470ea56..dd404aa72dfa3b328073a59b4c9e1fe6479ae162 100644 --- a/src/materials/alloys/Alloy.py +++ b/src/materials/alloys/Alloy.py @@ -1,3 +1,4 @@ +from typing import List import numpy as np from dataclasses import dataclass, field from src.materials.elements import Element, Ti, Al, V @@ -5,35 +6,54 @@ from src.materials.elements import interpolate_atomic_number, interpolate_atomic from src.materials.typedefs import ValueTypes, AssignmentType, PropertyTypes -# Alloy Base Class +# Base class for alloys, storing elemental composition and physical properties @dataclass class Alloy: - elements: list[Element] - composition: ValueTypes + elements: List[Element] + composition: ValueTypes # List of fractions summing to 1.0 temperature_solidus: float temperature_liquidus: float + # Properties to be calculated post-init based on composition atomic_number: float = field(init=False) atomic_mass: float = field(init=False) temperature_boil: float = field(init=False) - latent_heat_of_fusion: PropertyTypes = None - latent_heat_of_vaporization: PropertyTypes = None + # Optional properties with default values + density: PropertyTypes = None - thermal_expansion_coefficient: PropertyTypes = None + heat_capacity: PropertyTypes = None + heat_capacity_solidus: PropertyTypes = None + heat_capacity_liquidus: PropertyTypes = None + heat_conductivity: PropertyTypes = None + heat_conductivity_solidus: PropertyTypes = None + heat_conductivity_liquidus: PropertyTypes = None + + latent_heat: PropertyTypes = None + latent_heat_of_fusion: PropertyTypes = None + latent_heat_of_vaporization: PropertyTypes = None + thermal_diffusivity: PropertyTypes = None + thermal_diffusivity_solidus: PropertyTypes = None + thermal_diffusivity_liquidus: PropertyTypes = None + + thermal_expansion_coefficient: PropertyTypes = None + # Dictionary for storing calculated assignments assignments: AssignmentType = field(default_factory=dict, init=False) + # Calculate the solidification interval based on solidus and liquidus temperatures def solidification_interval(self) -> [float, float]: return [self.temperature_solidus, self.temperature_liquidus] + # Initialize properties based on elemental composition def __post_init__(self): + # Ensure the composition sums to 1, allowing for floating-point precision issues # if sum(self.composition) != 1.: # raise ValueError("The sum of the composition array has to be 1 got", sum(self.composition)) - if not np.isclose(sum(self.composition), 1.0, atol=1e-8): + if not np.isclose(sum(self.composition), 1.0, atol=1e-12): raise ValueError("The sum of the composition array must be 1, got", sum(self.composition)) self.atomic_number = interpolate_atomic_number(self.elements, self.composition) diff --git a/src/materials/alloys/SS316L/SS316L.py b/src/materials/alloys/SS316L/SS316L.py new file mode 100644 index 0000000000000000000000000000000000000000..bc2cf2a10c655bd9048b8c356ac05341397122a1 --- /dev/null +++ b/src/materials/alloys/SS316L/SS316L.py @@ -0,0 +1,83 @@ +from pathlib import Path +import numpy as np +import sympy as sp +from src.materials.alloys.Alloy import Alloy +from src.materials.elements import Fe, Cr, Mn, Ni +from src.materials.interpolators import interpolate_equidistant, interpolate_lookup +from src.materials.models import density_by_thermal_expansion, thermal_diffusivity_by_heat_conductivity +from src.materials.typedefs import VariableTypes +from src.materials.data_handler.data_handler import read_data + +def create_SS316L(T: VariableTypes) -> Alloy: + """ + Creates an Alloy instance for SS316L stainless steel with specific properties. + + Args: + T (VariableTypes): Temperature as a symbolic variable or numeric value. + + Returns: + Alloy: Initialized SS316L alloy with physical properties. + """ + # Define the alloy with specific elemental composition and phase transition temperatures + SS316L = Alloy( + elements=[Fe, Cr, Mn, Ni], + composition=[0.708, 0.192, 0.018, 0.082], # Composition: 70.8% Fe, 19.2% Cr, 1.8% Mn, 8.2% Ni + temperature_solidus=1683.68, # Solidus temperature in Kelvin (1683.68 K) + temperature_liquidus=1710.26 # Liquidus temperature in Kelvin (1710.26 K) + ) + + # Determine the base directory + base_dir = Path(__file__).parent # Directory of the current file + + # Paths to data files using relative paths + density_data_file_path = base_dir / 'density_temperature.txt' + heat_capacity_data_file_path = base_dir / 'heat_capacity_temperature.txt' + heat_conductivity_data_file_path = base_dir / 'heat_conductivity_temperature.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) + heat_conductivity_temp_array, heat_conductivity_array = read_data(heat_conductivity_data_file_path) + + # Ensure the data was loaded correctly + if not density_temp_array or not density_array or not heat_capacity_temp_array or not heat_capacity_array \ + or not heat_conductivity_temp_array or not heat_conductivity_array: + raise ValueError("Failed to load temperature or material data from the file.") + + # Set the thermal expansion coefficient for SS316L + SS316L.thermal_expansion_coefficient = 1.5e-5 # Thermal expansion coefficient in 1/K + + # Perform equidistant interpolation for the density at temperature T + density_result, sub_expr_density = interpolate_equidistant( + T, SS316L.temperature_solidus, 8, density_array, 'density') + # Update the alloy with the interpolated density value + SS316L.density = density_result + # Store the sub-expressions for symbolic evaluation and further processing + SS316L.assignments.update({"density": sub_expr_density}) + + # Specific heat capacity (J/(kg·K)) [Source: MatWeb] + SS316L.heat_capacity = 500 # Specific heat capacity in J/(kg·K) + + # Thermal conductivity (W/(m·K)) [Source: MatWeb] + SS316L.heat_conductivity = interpolate_lookup( + T, heat_conductivity_temp_array, heat_conductivity_array) # Thermal conductivity in W/(m·K) + + # Calculate thermal diffusivity from thermal conductivity, density, and heat capacity + SS316L.thermal_diffusivity = thermal_diffusivity_by_heat_conductivity( + SS316L.heat_conductivity, SS316L.density, SS316L.heat_capacity) + + return SS316L + +if __name__ == '__main__': + Temp = sp.Symbol('Temp') + alloy = create_SS316L(Temp) + + # Check if the sum of the composition is 1 + if not np.isclose(sum(alloy.composition), 1.0, atol=1e-12): + raise ValueError("The sum of the composition array must be 1, got", sum(alloy.composition)) + else: + print("The composition values sum to 1.0") + + # Print the composition of each element in the alloy + for i in range(len(alloy.composition)): + print(f"Element {alloy.elements[i]}: {alloy.composition[i]}") diff --git a/src/materials/alloys/SS316L/__init__.py b/src/materials/alloys/SS316L/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/materials/alloys/SS316L/density_temperature.txt b/src/materials/alloys/SS316L/density_temperature.txt new file mode 100644 index 0000000000000000000000000000000000000000..7adefc7b489f01ddc36e11f87966075299469981 --- /dev/null +++ b/src/materials/alloys/SS316L/density_temperature.txt @@ -0,0 +1,299 @@ +temperature density +3000.0 5.667564404 +2990.0 5.676952519 +2980.0 5.686342789 +2970.0 5.695735083 +2960.0 5.705129266 +2950.0 5.714525204 +2940.0 5.72392276 +2930.0 5.733321798 +2920.0 5.74272218 +2910.0 5.752123768 +2900.0 5.761526422 +2890.0 5.770930002 +2880.0 5.780334366 +2870.0 5.789739372 +2860.0 5.799144876 +2850.0 5.808550735 +2840.0 5.817956803 +2830.0 5.827362933 +2820.0 5.83676898 +2810.0 5.846174794 +2800.0 5.855580226 +2790.0 5.864985128 +2780.0 5.874389347 +2770.0 5.883792732 +2760.0 5.893195129 +2750.0 5.902596387 +2740.0 5.911996349 +2730.0 5.92139486 +2720.0 5.930791763 +2710.0 5.940186901 +2700.0 5.949580115 +2690.0 5.958971247 +2680.0 5.968360134 +2670.0 5.977746618 +2660.0 5.987130534 +2650.0 5.99651172 +2640.0 6.005890011 +2630.0 6.015265243 +2620.0 6.02463725 +2610.0 6.034005865 +2600.0 6.043370919 +2590.0 6.052732245 +2580.0 6.062089672 +2570.0 6.07144303 +2560.0 6.080792147 +2550.0 6.090136851 +2540.0 6.099476968 +2530.0 6.108812324 +2520.0 6.118142744 +2510.0 6.127468052 +2500.0 6.136788071 +2490.0 6.146102622 +2480.0 6.155411527 +2470.0 6.164714607 +2460.0 6.17401168 +2450.0 6.183302565 +2440.0 6.19258708 +2430.0 6.201865041 +2420.0 6.211136264 +2410.0 6.220400565 +2400.0 6.229657757 +2390.0 6.238907653 +2380.0 6.248150066 +2370.0 6.257384807 +2360.0 6.266611687 +2350.0 6.275830516 +2340.0 6.285041102 +2330.0 6.294243254 +2320.0 6.303436779 +2310.0 6.312621483 +2300.0 6.321797171 +2290.0 6.33096365 +2280.0 6.340120722 +2270.0 6.34926819 +2260.0 6.358405857 +2250.0 6.367533525 +2240.0 6.376650993 +2230.0 6.385758063 +2220.0 6.394854532 +2210.0 6.4039402 +2200.0 6.413014864 +2190.0 6.422078321 +2180.0 6.431130366 +2170.0 6.440170795 +2160.0 6.449199403 +2150.0 6.458215983 +2140.0 6.467220328 +2130.0 6.476212231 +2120.0 6.485191483 +2110.0 6.494157875 +2100.0 6.503111197 +2090.0 6.512051239 +2080.0 6.520977789 +2070.0 6.529890636 +2060.0 6.538789566 +2050.0 6.547674367 +2040.0 6.556544824 +2030.0 6.565400724 +2020.0 6.57424185 +2010.0 6.583067987 +2000.0 6.591878918 +1990.0 6.600674426 +1980.0 6.609454294 +1970.0 6.618218303 +1960.0 6.626966234 +1950.0 6.635697868 +1940.0 6.644412984 +1930.0 6.653111361 +1920.0 6.661792779 +1910.0 6.670457016 +1900.0 6.67910385 +1890.0 6.687733056 +1880.0 6.696344413 +1870.0 6.704937696 +1860.0 6.713512681 +1850.0 6.722069143 +1840.0 6.730606857 +1830.0 6.739125596 +1820.0 6.747625135 +1810.0 6.756105246 +1800.0 6.764565703 +1790.0 6.773006278 +1780.0 6.781426743 +1770.0 6.78982687 +1760.0 6.79820643 +1750.0 6.806565193 +1740.0 6.81490293 +1730.0 6.823219411 +1720.0 6.831514406 +1710.0 6.839787684 +1700.0 6.848039015 +1690.0 6.856268167 +1680.0 6.864474909 +1670.0 6.872659008 +1660.0 6.880820234 +1650.0 6.888958353 +1640.0 6.897073133 +1630.0 6.905164341 +1620.0 6.913231745 +1610.0 6.92127511 +1600.0 6.929294204 +1590.0 6.937288793 +1580.0 6.945258643 +1570.0 6.953203521 +1560.0 6.961123192 +1550.0 6.969017421 +1540.0 6.976885976 +1530.0 6.984728621 +1520.0 6.992545122 +1510.0 7.000335245 +1500.0 7.008098755 +1490.0 7.015835416 +1480.0 7.023544996 +1470.0 7.031227258 +1460.0 7.038881969 +1450.0 7.101066042 +1440.0 7.134387853 +1430.0 7.177458788 +1420.0 7.211193546 +1410.0 7.228319303 +1400.0 7.239681101 +1390.0 7.249455888 +1380.0 7.258134874 +1370.0 7.266781373 +1360.0 7.275378823 +1350.0 7.283907087 +1340.0 7.292372432 +1330.0 7.300806759 +1320.0 7.309120646 +1310.0 7.317361161 +1300.0 7.325511618 +1290.0 7.333644738 +1280.0 7.341683473 +1270.0 7.349597336 +1260.0 7.357432453 +1250.0 7.365195996 +1240.0 7.372887415 +1230.0 7.380522323 +1220.0 7.388029457 +1210.0 7.395402654 +1200.0 7.401625175 +1190.0 7.406659562 +1180.0 7.411685346 +1170.0 7.416702547 +1160.0 7.42171118 +1150.0 7.426711264 +1140.0 7.431702814 +1130.0 7.436685849 +1120.0 7.441660386 +1110.0 7.446626444 +1100.0 7.451584039 +1090.0 7.456533191 +1080.0 7.461473918 +1070.0 7.466406239 +1060.0 7.471330172 +1050.0 7.476245738 +1040.0 7.481152955 +1030.0 7.486051844 +1020.0 7.490942424 +1010.0 7.495824716 +1000.0 7.500698741 +990.0 7.505564519 +980.0 7.510422072 +970.0 7.515271421 +960.0 7.520112589 +950.0 7.524945596 +940.0 7.529770467 +930.0 7.534587223 +920.0 7.539395888 +910.0 7.544196486 +900.0 7.548989038 +890.0 7.553773571 +880.0 7.558550107 +870.0 7.563318673 +860.0 7.568079292 +850.0 7.57283199 +840.0 7.577576792 +830.0 7.582313725 +820.0 7.587042814 +810.0 7.591764087 +800.0 7.59647757 +790.0 7.601183289 +780.0 7.605881273 +770.0 7.61057155 +760.0 7.615254146 +750.0 7.619929092 +740.0 7.624596415 +730.0 7.629256145 +720.0 7.633908311 +710.0 7.638552943 +700.0 7.64319007 +690.0 7.647819723 +680.0 7.652441932 +670.0 7.657056729 +660.0 7.661664145 +650.0 7.666264211 +640.0 7.67085696 +630.0 7.675442422 +620.0 7.680020632 +610.0 7.684591621 +600.0 7.689155423 +590.0 7.693712072 +580.0 7.6982616 +570.0 7.702804042 +560.0 7.707339433 +550.0 7.711867807 +540.0 7.7163892 +530.0 7.720903645 +520.0 7.72541118 +510.0 7.72991184 +500.0 7.734405661 +490.0 7.73889268 +480.0 7.743372934 +470.0 7.74784646 +460.0 7.752313295 +450.0 7.756773477 +440.0 7.761227045 +430.0 7.765674036 +420.0 7.77011449 +410.0 7.774548445 +400.0 7.778975941 +390.0 7.783397018 +380.0 7.787811714 +370.0 7.792220072 +360.0 7.796622131 +350.0 7.801017932 +340.0 7.805407516 +330.0 7.809790925 +320.0 7.8141682 +310.0 7.818539384 +300.0 7.82290452 +290.0 7.827263649 +280.0 7.831616814 +270.0 7.83596406 +260.0 7.84030543 +250.0 7.844640967 +240.0 7.848970716 +230.0 7.853294721 +220.0 7.857613028 +210.0 7.861925681 +200.0 7.866232725 +190.0 7.870534208 +180.0 7.874830173 +170.0 7.879120669 +160.0 7.883405741 +150.0 7.887685437 +140.0 7.891959803 +130.0 7.896228887 +120.0 7.900492738 +110.0 7.904751403 +100.0 7.90900493 +90.0 7.913253369 +80.0 7.917496768 +70.0 7.921735177 +60.0 7.925968645 +50.0 7.930197222 +40.0 7.93442096 +30.0 7.938639907 diff --git a/src/materials/alloys/SS316L/heat_capacity_temperature.txt b/src/materials/alloys/SS316L/heat_capacity_temperature.txt new file mode 100644 index 0000000000000000000000000000000000000000..1522c9ed89ce00dbf4d6ad6a7e0f7457ddbb0af7 --- /dev/null +++ b/src/materials/alloys/SS316L/heat_capacity_temperature.txt @@ -0,0 +1,222 @@ +temperature specific_heat +3000.0 0.845 +2990.0 0.845 +2980.0 0.845 +2970.0 0.845 +2960.0 0.845 +2950.0 0.845 +2940.0 0.845 +2930.0 0.845 +2920.0 0.845 +2910.0 0.845 +2900.0 0.84501 +2890.0 0.84501 +2880.0 0.84501 +2870.0 0.84501 +2860.0 0.84501 +2850.0 0.84501 +2840.0 0.84501 +2830.0 0.84501 +2820.0 0.84501 +2810.0 0.845 +2800.0 0.845 +2790.0 0.845 +2780.0 0.845 +2770.0 0.845 +2760.0 0.845 +2750.0 0.845 +2740.0 0.845 +2730.0 0.845 +2720.0 0.845 +2710.0 0.845 +2700.0 0.845 +2690.0 0.845 +2680.0 0.845 +2670.0 0.845 +2660.0 0.845 +2650.0 0.845 +2640.0 0.845 +2630.0 0.845 +2620.0 0.845 +2610.0 0.845 +2600.0 0.84499 +2590.0 0.84499 +2580.0 0.84499 +2570.0 0.84499 +2560.0 0.84499 +2550.0 0.84499 +2540.0 0.84499 +2530.0 0.84499 +2520.0 0.84499 +2510.0 0.84499 +2500.0 0.84499 +2490.0 0.84499 +2480.0 0.84499 +2470.0 0.84499 +2460.0 0.84499 +2450.0 0.84498 +2440.0 0.84498 +2430.0 0.84498 +2420.0 0.84498 +2410.0 0.84498 +2400.0 0.84498 +2390.0 0.84498 +2380.0 0.84498 +2370.0 0.84498 +2360.0 0.84498 +2350.0 0.84498 +2340.0 0.84498 +2330.0 0.84498 +2320.0 0.84497 +2310.0 0.84497 +2300.0 0.84497 +2290.0 0.84497 +2280.0 0.84497 +2270.0 0.84497 +2260.0 0.84497 +2250.0 0.84497 +2240.0 0.84497 +2230.0 0.84497 +2220.0 0.84497 +2210.0 0.84496 +2200.0 0.84496 +2190.0 0.84496 +2180.0 0.84496 +2170.0 0.84496 +2160.0 0.84496 +2150.0 0.84496 +2140.0 0.84496 +2130.0 0.84496 +2120.0 0.84496 +2110.0 0.84496 +2100.0 0.84495 +2090.0 0.84495 +2080.0 0.84495 +2070.0 0.84495 +2060.0 0.84495 +2050.0 0.84495 +2040.0 0.84495 +2030.0 0.84495 +2020.0 0.84495 +2010.0 0.84495 +2000.0 0.84495 +1990.0 0.84494 +1980.0 0.84494 +1970.0 0.84494 +1960.0 0.84494 +1950.0 0.84494 +1940.0 0.84494 +1930.0 0.84494 +1920.0 0.84494 +1910.0 0.84494 +1900.0 0.84479 +1890.0 0.84457 +1880.0 0.84433 +1870.0 0.84407 +1860.0 0.8438 +1850.0 0.84351 +1840.0 0.84321 +1830.0 0.84289 +1820.0 0.84255 +1810.0 0.8422 +1800.0 0.84183 +1790.0 0.84146 +1780.0 0.84106 +1770.0 0.84066 +1760.0 0.84024 +1750.0 0.83981 +1740.0 0.83937 +1730.0 0.83891 +1720.0 0.83845 +1710.0 0.83797 +1700.0 0.83749 +1690.0 0.83699 +1680.0 0.83648 +1670.0 0.83597 +1660.0 0.83544 +1650.0 0.83491 +1640.0 0.83437 +1630.0 0.83382 +1620.0 0.83326 +1610.0 0.83269 +1600.0 0.83212 +1590.0 0.83154 +1580.0 0.83095 +1570.0 0.83035 +1560.0 0.82975 +1550.0 0.82915 +1540.0 0.82853 +1530.0 0.82512 +1520.0 0.82101 +1510.0 0.81696 +1500.0 0.81297 +1490.0 0.80902 +1480.0 0.80514 +1470.0 0.8013 +1460.0 0.79752 +1450.0 6.07776 +1440.0 3.83196 +1430.0 4.74244 +1420.0 2.20109 +1410.0 1.35042 +1400.0 1.04567 +1390.0 0.95028 +1380.0 0.90286 +1370.0 0.88798 +1360.0 0.87378 +1350.0 0.86021 +1340.0 0.84722 +1330.0 0.83482 +1320.0 0.82298 +1310.0 0.81168 +1300.0 0.80097 +1290.0 0.79062 +1280.0 0.78075 +1270.0 0.77133 +1260.0 0.76232 +1250.0 0.75372 +1240.0 0.74553 +1230.0 0.73775 +1220.0 0.73031 +1210.0 0.72321 +1200.0 0.67791 +1190.0 0.67579 +1180.0 0.67368 +1170.0 0.67158 +1160.0 0.66948 +1150.0 0.6674 +1140.0 0.66533 +1130.0 0.66325 +1120.0 0.66119 +1110.0 0.65909 +1100.0 0.65705 +1090.0 0.65502 +1080.0 0.65298 +1070.0 0.65096 +1060.0 0.64893 +1050.0 0.64693 +1040.0 0.64494 +1030.0 0.64294 +1020.0 0.64096 +1010.0 0.63897 +1000.0 0.637 +990.0 0.63503 +980.0 0.63307 +970.0 0.63112 +960.0 0.62919 +950.0 0.62724 +940.0 0.6253 +930.0 0.62338 +920.0 0.62146 +910.0 0.61955 +900.0 0.61764 +890.0 0.61574 +880.0 0.61384 +870.0 0.62728 +860.0 0.62424 +850.0 0.62127 +840.0 0.61839 +830.0 0.64959 +820.0 0.64516 +810.0 0.64087 +800.0 0.65115 diff --git a/src/materials/alloys/SS316L/heat_conductivity_temperature.txt b/src/materials/alloys/SS316L/heat_conductivity_temperature.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3550349e1a0eba5ac5a2eccc0d04181821dd99d --- /dev/null +++ b/src/materials/alloys/SS316L/heat_conductivity_temperature.txt @@ -0,0 +1,299 @@ +temperature thermal_conductivity +3000.0 54.72334648 +2990.0 54.57108027 +2980.0 54.41881406 +2970.0 54.26654784 +2960.0 54.11428163 +2950.0 53.96201542 +2940.0 53.8097492 +2930.0 53.65748299 +2920.0 53.50521678 +2910.0 53.35295056 +2900.0 53.20068435 +2890.0 53.04841813 +2880.0 52.89615192 +2870.0 52.74388571 +2860.0 52.59161949 +2850.0 52.43935328 +2840.0 52.28708707 +2830.0 52.13482085 +2820.0 51.98255464 +2810.0 51.83028843 +2800.0 51.67802221 +2790.0 51.525756 +2780.0 51.37348978 +2770.0 51.22122357 +2760.0 51.06895736 +2750.0 50.91669114 +2740.0 50.76442493 +2730.0 50.61215872 +2720.0 50.4598925 +2710.0 50.30762629 +2700.0 50.15536008 +2690.0 50.00309386 +2680.0 49.85082765 +2670.0 49.69856143 +2660.0 49.54629522 +2650.0 49.39402901 +2640.0 49.24176279 +2630.0 49.08949658 +2620.0 48.93723037 +2610.0 48.78496415 +2600.0 48.63269794 +2590.0 48.48043173 +2580.0 48.32816551 +2570.0 48.1758993 +2560.0 48.02363308 +2550.0 47.87136687 +2540.0 47.71910066 +2530.0 47.56683444 +2520.0 47.41456823 +2510.0 47.26230202 +2500.0 47.1100358 +2490.0 46.95776959 +2480.0 46.80550338 +2470.0 46.65323716 +2460.0 46.50097095 +2450.0 46.34870473 +2440.0 46.19643852 +2430.0 46.04417231 +2420.0 45.89190609 +2410.0 45.73963988 +2400.0 45.58737367 +2390.0 45.43510745 +2380.0 45.28284124 +2370.0 45.13057503 +2360.0 44.97830881 +2350.0 44.8260426 +2340.0 44.67377638 +2330.0 44.52151017 +2320.0 44.36924396 +2310.0 44.21697774 +2300.0 44.06471153 +2290.0 43.91244532 +2280.0 43.7601791 +2270.0 43.60791289 +2260.0 43.45564668 +2250.0 43.30338046 +2240.0 43.15111425 +2230.0 42.99884803 +2220.0 42.84658182 +2210.0 42.69431561 +2200.0 42.54204939 +2190.0 42.38978318 +2180.0 42.23751697 +2170.0 42.08525075 +2160.0 41.93298454 +2150.0 41.78071833 +2140.0 41.62845211 +2130.0 41.4761859 +2120.0 41.32391968 +2110.0 41.17165347 +2100.0 41.01938726 +2090.0 40.86712104 +2080.0 40.71485483 +2070.0 40.56258862 +2060.0 40.4103224 +2050.0 40.25805619 +2040.0 40.10578998 +2030.0 39.95352376 +2020.0 39.80125755 +2010.0 39.64899133 +2000.0 39.49672512 +1990.0 39.34445891 +1980.0 39.19219269 +1970.0 39.03992648 +1960.0 38.88766027 +1950.0 38.73539405 +1940.0 38.58312784 +1930.0 38.43086163 +1920.0 38.27859541 +1910.0 38.1263292 +1900.0 37.97406298 +1890.0 37.82179677 +1880.0 37.66953056 +1870.0 37.51726434 +1860.0 37.36499813 +1850.0 37.21273192 +1840.0 37.0604657 +1830.0 36.90819949 +1820.0 36.75593327 +1810.0 36.60366706 +1800.0 36.45140085 +1790.0 36.29913463 +1780.0 36.14686842 +1770.0 35.99460221 +1760.0 35.84233599 +1750.0 35.69006978 +1740.0 35.53780357 +1730.0 35.38553735 +1720.0 35.23327114 +1710.0 35.08100492 +1700.0 34.92873871 +1690.0 34.7764725 +1680.0 34.62420628 +1670.0 34.47194007 +1660.0 34.31967386 +1650.0 34.16740764 +1640.0 34.01514143 +1630.0 33.86287522 +1620.0 33.710609 +1610.0 33.55834279 +1600.0 33.40607657 +1590.0 33.25381036 +1580.0 33.10154415 +1570.0 32.94927793 +1560.0 32.79701172 +1550.0 32.64474551 +1540.0 32.49247929 +1530.0 32.34021308 +1520.0 32.18794687 +1510.0 32.03568065 +1500.0 31.88341444 +1490.0 31.73114822 +1480.0 31.57888201 +1470.0 31.4266158 +1460.0 31.27434958 +1450.0 32.56807438 +1440.0 33.21226612 +1430.0 33.9112371 +1420.0 33.98623511 +1410.0 33.86916582 +1400.0 33.68767847 +1390.0 33.48563596 +1380.0 33.28257534 +1370.0 33.08442323 +1360.0 32.89134414 +1350.0 32.70289252 +1340.0 32.51888227 +1330.0 32.33878905 +1320.0 32.16280676 +1310.0 31.99055184 +1300.0 31.82202582 +1290.0 31.65641555 +1280.0 31.49403674 +1270.0 31.33447241 +1260.0 31.17784189 +1250.0 31.02361972 +1240.0 30.87151334 +1230.0 30.72167947 +1220.0 30.57412174 +1210.0 30.42836476 +1200.0 30.29257382 +1190.0 30.16567194 +1180.0 30.03877002 +1170.0 29.9118681 +1160.0 29.78496615 +1150.0 29.65806423 +1140.0 29.53116225 +1130.0 29.40426027 +1120.0 29.27735829 +1110.0 29.15045629 +1100.0 29.02355431 +1090.0 28.8966523 +1080.0 28.76975029 +1070.0 28.64284828 +1060.0 28.5159463 +1050.0 28.38904426 +1040.0 28.26214225 +1030.0 28.13524021 +1020.0 28.00833817 +1010.0 27.88143616 +1000.0 27.75453412 +990.0 27.62763209 +980.0 27.50073008 +970.0 27.37382806 +960.0 27.24692603 +950.0 27.12002399 +940.0 26.99312195 +930.0 26.86621991 +920.0 26.73931788 +910.0 26.61241584 +900.0 26.4855138 +890.0 26.35861177 +880.0 26.23170973 +870.0 26.10480769 +860.0 25.97790565 +850.0 25.85100362 +840.0 25.72410158 +830.0 25.59719954 +820.0 25.4702975 +810.0 25.34339547 +800.0 25.21649345 +790.0 25.08959141 +780.0 24.96268938 +770.0 24.83578734 +760.0 24.7088853 +750.0 24.58198326 +740.0 24.45508122 +730.0 24.32817919 +720.0 24.20127715 +710.0 24.07437511 +700.0 23.94747307 +690.0 23.82057104 +680.0 23.693669 +670.0 23.56676696 +660.0 23.43986492 +650.0 23.31296289 +640.0 23.18606085 +630.0 23.05915881 +620.0 22.93225677 +610.0 22.80535474 +600.0 22.6784527 +590.0 22.55155066 +580.0 22.42464862 +570.0 22.29774658 +560.0 22.17084455 +550.0 22.04394251 +540.0 21.91704047 +530.0 21.79013843 +520.0 21.6632364 +510.0 21.53633436 +500.0 21.40943232 +490.0 21.28253028 +480.0 21.15562825 +470.0 21.02872621 +460.0 20.90182417 +450.0 20.77492213 +440.0 20.64802009 +430.0 20.52111806 +420.0 20.39421602 +410.0 20.26731398 +400.0 20.14041194 +390.0 20.01350991 +380.0 19.88660787 +370.0 19.75970583 +360.0 19.63280379 +350.0 19.50590176 +340.0 19.37899972 +330.0 19.25209768 +320.0 19.12519564 +310.0 18.9982936 +300.0 18.87139157 +290.0 18.74448953 +280.0 18.61758749 +270.0 18.49068545 +260.0 18.36378342 +250.0 18.23688138 +240.0 18.10997934 +230.0 17.9830773 +220.0 17.85617527 +210.0 17.72927323 +200.0 17.60237119 +190.0 17.47546915 +180.0 17.34856711 +170.0 17.22166508 +160.0 17.09476304 +150.0 16.967861 +140.0 16.84095896 +130.0 16.71405693 +120.0 16.58715489 +110.0 16.46025285 +100.0 16.33335081 +90.0 16.20644878 +80.0 16.07954674 +70.0 15.9526447 +60.0 15.82574266 +50.0 15.69884062 +40.0 15.57193859 +30.0 15.44503655 diff --git a/src/materials/alloys/Ti6Al4V.py b/src/materials/alloys/Ti6Al4V.py index d07e1f1182013bb7606488df0a7ed5ae23564b25..6de8dcd042688c18bd52f5548737f83f83311a2e 100644 --- a/src/materials/alloys/Ti6Al4V.py +++ b/src/materials/alloys/Ti6Al4V.py @@ -1,56 +1,85 @@ +import numpy as np import sympy as sp 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.elements import Ti, Al, V +from src.materials.interpolators import interpolate_equidistant, interpolate_lookup +from src.materials.models import density_by_thermal_expansion, thermal_diffusivity_by_heat_conductivity from src.materials.typedefs import VariableTypes def create_Ti6Al4V(T: VariableTypes) -> Alloy: - # 90% Ti, 6% Al, 4% V + """ + Creates an Alloy instance for Ti6Al4V with specific properties. + + Args: + T (VariableTypes): Temperature as a symbolic variable or numeric value. + + Returns: + Alloy: Initialized Ti6Al4V alloy with physical properties. + """ + # Define alloy with specific elemental composition and phase transition temperatures Ti6Al4V = Alloy( elements=[Ti, Al, V], - composition=[0.90, 0.06, 0.04], - temperature_solidus=1878.0, - temperature_liquidus=1928.0 + composition=[0.90, 0.06, 0.04], # 90% Ti, 6% Al, 4% V + temperature_solidus=1878.0, # Temperature solidus in Kelvin + temperature_liquidus=1928.0 # Temperature liquidus in Kelvin ) - Ti6Al4V.latent_heat_of_fusion = 290000.0 # m²/s² - Ti6Al4V.thermal_expansion_coefficient = 10e-6 # /K Ref[6] - - # ---------- density ---------- - - '''Ti6Al4V.density = 4430.0 # kg/m³ Ref [5] + # Set properties specific to Ti6Al4V + # Thermal expansion coefficient (1/K) [Source: MatWeb] + Ti6Al4V.thermal_expansion_coefficient = 8.6e-6 # 1/K - Ti6Al4V.density = models.density_by_thermal_expansion( - T, Constants.temperature_room, 4430, Ti6Al4V.thermal_expansion_coefficient)''' + # Define density using models and interpolations for different temperature ranges + # Density (kg/m³) [Source: MatWeb] + Ti6Al4V.density = 4430.0 # kg/m³ # Using interpolate_equidistant for density - density_result, sub_expr_density = interpolators.interpolate_equidistant( - T, 1878, 8, [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0], 'density') + T_array = np.linspace(Ti6Al4V.temperature_solidus, Ti6Al4V.temperature_liquidus, 7) + # density_array = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0] + density_array = [density_by_thermal_expansion( + T_i, Constants.temperature_room, 4430, Ti6Al4V.thermal_expansion_coefficient) for T_i in T_array] + # Perform equidistant interpolation for the density at temperature T + density_result, sub_expr_density = interpolate_equidistant( + T, Ti6Al4V.temperature_solidus, 8, density_array, 'density') + # Update the alloy with the interpolated density value Ti6Al4V.density = density_result + # Store the sub-expressions for symbolic evaluation and further processing Ti6Al4V.assignments.update({"density": sub_expr_density}) - # Using interpolate_lookup for density - '''Ti6Al4V.density = interpolators.interpolate_lookup( - T, Ti6Al4V.solidification_interval(), [4236.3, 4227.]) + # Specific heat capacity (J/(kg·K)) [Source: MatWeb] + Ti6Al4V.heat_capacity = 526 # J/(kg·K) - 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])''' + # Specific heat capacity at solidus temperature (J/(kg·K)) [Source: MatWeb] + Ti6Al4V.heat_capacity_solidus = 520 # J/(kg·K) - # ---------- heat_capacity ---------- + # Specific heat capacity at liquidus temperature (J/(kg·K)) [Source: MatWeb] + Ti6Al4V.heat_capacity_liquidus = 540 # J/(kg·K) - Ti6Al4V.heat_capacity = 526 + # Thermal conductivity (W/(m·K)) [Source: MatWeb] + Ti6Al4V.heat_conductivity = interpolate_lookup( + T, Ti6Al4V.solidification_interval(), [6.7, 32.0]) # W/(m·K) - # ---------- heat_conductivity ---------- + # Thermal conductivity at solidus temperature (W/(m·K)) [Source: MatWeb] + Ti6Al4V.heat_conductivity_solidus = 16.5 # W/(m·K) - Ti6Al4V.heat_conductivity = 25 + # Thermal conductivity at liquidus temperature (W/(m·K)) [Source: MatWeb] + Ti6Al4V.heat_conductivity_liquidus = 18.0 # W/(m·K) - # ---------- thermal_diffusivity ---------- + # Latent heat of fusion (J/kg) [Source: MatWeb] + Ti6Al4V.latent_heat_of_fusion = 290000.0 # J/kg - Ti6Al4V.thermal_diffusivity = models.thermal_diffusivity_by_heat_conductivity( + # Latent heat of vaporization (J/kg) [Source: MatWeb] + Ti6Al4V.latent_heat_of_vaporization = 8.86e6 # J/kg + + # Thermal diffusivity at solidus temperature (m²/s) [Source: MatWeb] + Ti6Al4V.thermal_diffusivity_solidus = 4.1e-6 # m²/s + + # Thermal diffusivity at liquidus temperature (m²/s) [Source: MatWeb] + Ti6Al4V.thermal_diffusivity_liquidus = 4.3e-6 # m²/s + + # Calculate thermal diffusivity from conductivity, density, and heat capacity + Ti6Al4V.thermal_diffusivity = thermal_diffusivity_by_heat_conductivity( Ti6Al4V.heat_conductivity, Ti6Al4V.density, Ti6Al4V.heat_capacity) return Ti6Al4V @@ -60,23 +89,28 @@ if __name__ == '__main__': Temp = sp.Symbol('Temp') alloy = create_Ti6Al4V(Temp) - print("Testing Ti6Al4V with symbolic temperature:") - print('Ti6Al4V Properties:') + print("Ti-6Al-4V Alloy Properties:") + print(f"Density: {alloy.density}") + print(f"Heat Conductivity: {alloy.heat_conductivity}") + print(f"Thermal Diffusivity: {alloy.thermal_diffusivity}") + + # Testing Ti6Al4V with symbolic temperature + print("\nTesting Ti6Al4V with symbolic temperature:") for field in vars(alloy): print(f"{field} = {alloy.__getattribute__(field)}") # Test interpolate_equidistant print("\nTesting interpolate_equidistant:") test_temp = 1850.0 # Example temperature value - result, _ = interpolators.interpolate_equidistant( + result, _ = interpolate_equidistant( test_temp, 1820, 20.0, [700, 800, 900, 1000, 1100, 1200], 'heat_capacity') print(f"Interpolated heat capacity at T={test_temp} using interpolate_equidistant: {result}") - _, assignments = interpolators.interpolate_equidistant( + _, assignments = interpolate_equidistant( Temp, 1820, 20.0, [700, 800, 900, 1000, 1100, 1200], 'heat_capacity') print(f"Assignments: {assignments}") - result_density, _ = interpolators.interpolate_equidistant( + result_density, _ = interpolate_equidistant( test_temp, 1878, 8, [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0], 'density') print(f"Interpolated density at T={test_temp} using interpolate_equidistant: {result_density}") @@ -84,7 +118,7 @@ if __name__ == '__main__': print("\nTesting interpolate_lookup:") test_T_array = [1878.0, 1884.2, 1894.7, 1905.3, 1915.8, 1926.3, 1928.0] test_v_array = [4236.3, 4234.9, 4233.6, 4232.3, 4230.9, 4229.7, 4227.0] - result_lookup = interpolators.interpolate_lookup( + result_lookup = interpolate_lookup( Temp, test_T_array, test_v_array) print(f"Interpolated value using interpolate_lookup: {result_lookup}") @@ -92,12 +126,11 @@ if __name__ == '__main__': heat_conductivity = 500 # Example value for testing density = 5000 # Example value for testing heat_capacity = 600 # Example value for testing - thermal_diffusivity = models.thermal_diffusivity_by_heat_conductivity( + thermal_diffusivity = thermal_diffusivity_by_heat_conductivity( heat_conductivity, density, heat_capacity) print(f"Calculated thermal diffusivity: {thermal_diffusivity}") + # Uncomment below lines if plotting is needed # sp.plot(alloy.heat_conductivity, (Temp, 1800, 2000)) - # sp.plot(alloy.density, (Temp, 1800, 2000)) - # sp.plot(alloy.heat_capacity.subs([(alloy.assignments['heat_capacity'][1][0], alloy.assignments['heat_capacity'][1][1]), (alloy.assignments['heat_capacity'][0][0], alloy.assignments['heat_capacity'][0][1])]), (Temp, 1800, 2000)) diff --git a/src/materials/assignment_converter.py b/src/materials/assignment_converter.py index 630b681ad495374d4756b7800f1b6c4fc4bed545..f8f0a304f5ee7db4ae5975e29335f210edb5af3b 100644 --- a/src/materials/assignment_converter.py +++ b/src/materials/assignment_converter.py @@ -1,10 +1,48 @@ +import numpy as np import pystencils as ps from pystencils.types.quick import * from pystencils.sympyextensions.typed_sympy import CastFunc -from src.materials.typedefs import type_mapping + + +def type_mapping(type_str: str): + """ + Maps a string representation of a type to a corresponding numpy or pystencils data type. + + Parameters: + type_str (str): The string representation of the type (e.g., "double[]", "float[]"). + + Returns: + Union[np.dtype, Arr]: The corresponding numpy or pystencils data type. + - "double[]" maps to Arr(Fp(64)) which represents a 64-bit floating point array. + - "float[]" maps to Arr(Fp(32)) which represents a 32-bit floating point array. + - Other type strings are mapped to corresponding numpy data types. + """ + if type_str == "double[]": + return Arr(Fp(64)) # 64-bit floating point array + elif type_str == "float[]": + return Arr(Fp(32)) # 32-bit floating point array + else: + return np.dtype(type_str) # Default to numpy data type def assignment_converter(assignments_items): + """ + Converts the assignment data from the Alloy class to pystencils-compatible format. + + Parameters: + assignments_items (Dict[str, List[Assignment]]): A dictionary where each key is a label (string) and each value is a list of `Assignment` objects. + Each `Assignment` object should have the following attributes: + - lhs (sp.Symbol): The left-hand side of the assignment, which is a symbolic variable. It should have a `name` and a `type` attribute. + - rhs (Union[tuple, sp.Expr]): The right-hand side of the assignment, which can be a tuple or a sympy expression. + - lhs_type (str): A string representing the type of the left-hand side, indicating the data type (e.g., "double[]", "float[]"). + + Returns: + Tuple[List[ps.Assignment], Dict[Assignment, ps.TypedSymbol]]: + - A list of `pystencils.Assignment` objects, each representing an assignment in the pystencils format. + This list includes assignments where the `rhs` is directly assigned or cast to the appropriate type. + - A dictionary mapping each original `Assignment` object to its corresponding `pystencils.TypedSymbol`. + The dictionary maps `sp.Symbol` objects to `pystencils.TypedSymbol` instances, allowing for easy retrieval of types and assignments. + """ subexp = [] subs = {} # Iterate over the dictionary items @@ -16,10 +54,7 @@ def assignment_converter(assignments_items): data_symbol = ps.TypedSymbol(assignment.lhs.name, ps_type) if isinstance(ps_type, Arr): subexp.append(ps.Assignment(data_symbol, assignment.rhs)) - else: - # this is needed for the sp.floor, we want use it as index but floor returns a double - subexp.append( - ps.Assignment(data_symbol, CastFunc(assignment.rhs, ps_type)) - ) + else: # needed for the sp.floor in interpolate_equidistant to cast it to an int from double + subexp.append(ps.Assignment(data_symbol, CastFunc(assignment.rhs, ps_type))) subs[assignment.lhs] = data_symbol return subexp, subs diff --git a/src/materials/constants.py b/src/materials/constants.py index a1caa883ca6ccca913d92a1ec261d2ec64d1ed8a..c819919155129ba629a05c01d386f326eda2f023 100644 --- a/src/materials/constants.py +++ b/src/materials/constants.py @@ -3,6 +3,18 @@ from dataclasses import dataclass @dataclass class Constants: - temperature_room = 298.15 # k - N_a = 6.022141e23 # /mol - u = 1.660538e-27 # kg + """ + A dataclass to store fundamental constants. + + Attributes: + temperature_room (float): Room temperature in Kelvin. + N_a (float): Avogadro's number, the number of constituent particles (usually atoms or molecules) in one mole of a given substance. + u (float): Atomic mass unit in kilograms. + e (float): Elementary charge, the electric charge carried by a single proton or the magnitude of the electric charge carried by a single electron. + speed_of_light (float): Speed of light in vacuum in meters per second. + """ + temperature_room: float = 298.15 # Room temperature in Kelvin + N_a: float = 6.022141e23 # Avogadro's number, /mol + u: float = 1.660538e-27 # Atomic mass unit, kg + e: float = 1.60217657e-19 # Elementary charge, C + speed_of_light: float = 0.299792458e9 # Speed of light, m/s diff --git a/src/materials/data_handler/__init__.py b/src/materials/data_handler/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/materials/data_handler/data_handler.py b/src/materials/data_handler/data_handler.py new file mode 100644 index 0000000000000000000000000000000000000000..93db0e3bd4cd417c829f327a3a07362477745e92 --- /dev/null +++ b/src/materials/data_handler/data_handler.py @@ -0,0 +1,63 @@ +import os + +def read_data(file_path): + temperatures = [] + thermal_conductivities = [] + + try: + with open(file_path, 'r', newline='') as file: + for row in file.readlines(): + columns = row.strip().split() + if len(columns) == 2: + try: + temp = float(columns[0]) + prop = float(columns[1]) + temperatures.append(temp) + thermal_conductivities.append(prop) + except ValueError: + print(f"Warning: Skipping row with invalid data (cannot convert to float): {row}") + else: + print(f"Warning: Skipping row with missing or extra columns: {row}") + + # Check if we have any valid data + if not temperatures or len(temperatures) != len(thermal_conductivities): + print(f"Error: The file {file_path} does not contain valid data with matching columns.") + return [], [] + + return temperatures, thermal_conductivities + except FileNotFoundError: + print(f"Error: The file {file_path} does not exist.") + return [], [] + except IOError as e: + print(f"An I/O error occurred: {e}") + return [], [] + except Exception as e: + print(f"An unexpected error occurred: {e}") + return [], [] + +def print_results(file_path, temperatures, thermal_conductivities): + print(f"Testing: {os.path.basename(file_path).replace('.txt', '').replace('_', ' ').title()}") + print(f"File Path: {file_path}") + print() + print(f"Temperature: {temperatures}") + print(f"Thermal Conductivity: {thermal_conductivities}") + print("-" * 40) + +def run_tests(): + # Define test cases + test_cases = [ + {"name": "Normal Case", "file_path": "/local/ca00xebo/repos/walberla/src/materials/data_handler/test_data_normal.txt"}, + {"name": "Missing Columns", "file_path": "/local/ca00xebo/repos/walberla/src/materials/data_handler/test_data_missing_columns.txt"}, + {"name": "Mismatched Columns", "file_path": "/local/ca00xebo/repos/walberla/src/materials/data_handler/test_data_mismatched_columns.txt"}, + {"name": "Invalid Data", "file_path": "/local/ca00xebo/repos/walberla/src/materials/data_handler/test_data_invalid_data.txt"}, + {"name": "Empty File", "file_path": "/local/ca00xebo/repos/walberla/src/materials/data_handler/test_data_empty.txt"}, + {"name": "File with Only Header", "file_path": "/local/ca00xebo/repos/walberla/src/materials/data_handler/test_data_header_only.txt"} + ] + + for case in test_cases: + print(f"Running test: {case['name']}") + temp, prop = read_data(case['file_path']) + print_results(case['file_path'], temp, prop) + +if __name__ == "__main__": + run_tests() \ No newline at end of file diff --git a/src/materials/data_handler/test_data_empty.txt b/src/materials/data_handler/test_data_empty.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/materials/data_handler/test_data_header_only.txt b/src/materials/data_handler/test_data_header_only.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3a214150bc4d5fb87db6d7d5723bdfcd71617dc --- /dev/null +++ b/src/materials/data_handler/test_data_header_only.txt @@ -0,0 +1 @@ +Temperature MaterialProperty diff --git a/src/materials/data_handler/test_data_invalid_data.txt b/src/materials/data_handler/test_data_invalid_data.txt new file mode 100644 index 0000000000000000000000000000000000000000..74003ea55ea902ee61fadfca415d3149d04ce702 --- /dev/null +++ b/src/materials/data_handler/test_data_invalid_data.txt @@ -0,0 +1,3 @@ +3000 54.72334648 +3100 Invalid +3200 56.34567890 diff --git a/src/materials/data_handler/test_data_mismatched_columns.txt b/src/materials/data_handler/test_data_mismatched_columns.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6891e09c6eacbe15ea02ebef9fcecfc4cd99de7 --- /dev/null +++ b/src/materials/data_handler/test_data_mismatched_columns.txt @@ -0,0 +1,4 @@ +3000 54.72334648 1 +3100 55.23456789 +3200 56.34567890 2 3 +3300 57.45678901 \ No newline at end of file diff --git a/src/materials/data_handler/test_data_missing_columns.txt b/src/materials/data_handler/test_data_missing_columns.txt new file mode 100644 index 0000000000000000000000000000000000000000..c27214aa4dcf9b841a9391092c230f47fffb0287 --- /dev/null +++ b/src/materials/data_handler/test_data_missing_columns.txt @@ -0,0 +1,3 @@ +3000 54.72334648 +3100 +3200 56.34567890 diff --git a/src/materials/data_handler/test_data_normal.txt b/src/materials/data_handler/test_data_normal.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6686ad8be685f60de8f53ed5ac1f84c117ac935 --- /dev/null +++ b/src/materials/data_handler/test_data_normal.txt @@ -0,0 +1,3 @@ +3000 54.72334648 +3100 55.23456789 +3200 56.34567890 diff --git a/src/materials/elements.py b/src/materials/elements.py index 17cf2e7c19664c374243911df163cf2fdf075c48..0a6602725d598d14c64e4abab55a0e0846eedbf3 100644 --- a/src/materials/elements.py +++ b/src/materials/elements.py @@ -6,6 +6,7 @@ from src.materials.constants import Constants # Element Data Class @dataclass class Element: + name: str atomic_number: float atomic_mass: float temperature_melt: float @@ -14,52 +15,137 @@ class Element: latent_heat_of_vaporization: float +# NIST: National Institute of Standards and Technology +# RSC: Royal Society of Chemistry +# CRC: CRC Handbook of Chemistry and Physics + 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 + name="Titanium", + atomic_number=22, # Atomic number = 22 / Source: Periodic Table + atomic_mass=47.867 * Constants.u, # Atomic mass = 47.867 u / Source: NIST + temperature_melt=1941, # Melting temperature = 1941 K / Source: RSC + temperature_boil=3533, # Boiling temperature = 3533 K / Source: RSC + latent_heat_of_fusion=18700, # Latent heat of fusion = 18700 J/kg / Source: CRC + latent_heat_of_vaporization=427000 # Latent heat of vaporization = 427000 J/kg / Source: CRC ) - 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 + name="Aluminium", + atomic_number=13, # Atomic number = 13 / Source: Periodic Table + atomic_mass=26.9815384 * Constants.u, # Atomic mass = 26.9815384 u / Source: NIST + temperature_melt=933.35, # Melting temperature = 933.35 K / Source: RSC + temperature_boil=2743, # Boiling temperature = 2743 K / Source: RSC + latent_heat_of_fusion=10700, # Latent heat of fusion = 10700 J/kg / Source: CRC + latent_heat_of_vaporization=284000 # Latent heat of vaporization = 284000 J/kg / Source: CRC ) - 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 + name="Vanadium", + atomic_number=23, # Atomic number = 23 / Source: Periodic Table + atomic_mass=50.9415 * Constants.u, # Atomic mass = 50.9415 u / Source: NIST + temperature_melt=2183, # Melting temperature = 2183 K / Source: RSC + temperature_boil=3680, # Boiling temperature = 3680 K / Source: RSC + latent_heat_of_fusion=21500, # Latent heat of fusion = 21500 J/kg / Source: CRC + latent_heat_of_vaporization=444000 # Latent heat of vaporization = 444000 J/kg / Source: CRC +) + +Fe = Element( + name="Iron", + atomic_number=26, # Atomic number = 26 / Source: Periodic Table + atomic_mass=55.845 * Constants.u, # Atomic mass = 55.845 u / Source: NIST + temperature_melt=1811, # Melting temperature = 1811 K / Source: RSC + temperature_boil=3134, # Boiling temperature = 3134 K / Source: RSC + latent_heat_of_fusion=13800, # Latent heat of fusion = 13800 J/kg / Source: CRC + latent_heat_of_vaporization=340000 # Latent heat of vaporization = 340000 J/kg / Source: CRC +) + +Cr = Element( + name="Chromium", + atomic_number=24, # Atomic number = 24 / Source: Periodic Table + atomic_mass=51.9961 * Constants.u, # Atomic mass = 51.9961 u / Source: NIST + temperature_melt=2180, # Melting temperature = 2180 K / Source: RSC + temperature_boil=2944, # Boiling temperature = 2944 K / Source: RSC + latent_heat_of_fusion=16500, # Latent heat of fusion = 16500 J/kg / Source: CRC + latent_heat_of_vaporization=344000 # Latent heat of vaporization = 344000 J/kg / Source: CRC +) + +Mn = Element( + name="Manganese", + atomic_number=25, # Atomic number = 25 / Source: Periodic Table + atomic_mass=54.938045 * Constants.u, # Atomic mass = 54.938045 u / Source: NIST + temperature_melt=1519, # Melting temperature = 1519 K / Source: RSC + temperature_boil=2334, # Boiling temperature = 2334 K / Source: RSC + latent_heat_of_fusion=12500, # Latent heat of fusion = 12500 J/kg / Source: CRC + latent_heat_of_vaporization=220000 # Latent heat of vaporization = 220000 J/kg / Source: CRC +) + +Ni = Element( + name="Nickel", + atomic_number=28, # Atomic number = 28 / Source: Periodic Table + atomic_mass=58.6934 * Constants.u, # Atomic mass = 58.6934 u / Source: NIST + temperature_melt=1728, # Melting temperature = 1728 K / Source: RSC + temperature_boil=3186, # Boiling temperature = 3186 K / Source: RSC + latent_heat_of_fusion=17200, # Latent heat of fusion = 17200 J/kg / Source: CRC + latent_heat_of_vaporization=377000 # Latent heat of vaporization = 377000 J/kg / Source: CRC ) def interpolate(values, composition) -> float: + """ + Interpolates a property based on its values and composition. + + Args: + values (list): List of property values. + composition (list): List of composition percentages. + + Returns: + float: Interpolated property value. + """ c = np.asarray(composition) v = np.asarray(values) return float(np.sum(c * v)) def interpolate_atomic_number(elements, composition) -> float: + """ + Interpolates the atomic number based on the elements and their composition. + + Args: + elements (list[Element]): List of elements. + composition (list[float]): List of composition percentages. + + Returns: + float: Interpolated atomic number. + """ values = [element.atomic_number for element in elements] return interpolate(values, composition) def interpolate_temperature_boil(elements, composition) -> float: + """ + Interpolates the boiling temperature based on the elements and their composition. + + Args: + elements (list[Element]): List of elements. + composition (list[float]): List of composition percentages. + + Returns: + float: Interpolated boiling temperature. + """ values = [element.temperature_boil for element in elements] return interpolate(values, composition) def interpolate_atomic_mass(elements, composition) -> float: + """ + Interpolates the atomic mass based on the elements and their composition. + + Args: + elements (list[Element]): List of elements. + composition (list[float]): List of composition percentages. + + Returns: + float: Interpolated atomic mass. + """ values = [element.atomic_mass for element in elements] return interpolate(values, composition) diff --git a/src/materials/interpolators.py b/src/materials/interpolators.py index b75ad6707a7a49ac0bbd3a0b36321cb2a1880d35..0ac843113039010756ae415260c6f3cbcc6d93ba 100644 --- a/src/materials/interpolators.py +++ b/src/materials/interpolators.py @@ -3,27 +3,39 @@ import sympy as sp from src.materials.typedefs import Assignment, ValueTypes, PropertyTypes, VariableTypes -def interpolate_equidistant(T: VariableTypes, T_base: float, T_incr: float, v_array: ValueTypes, - label: str) -> tuple[sp.Expr, list[Assignment]]: +def interpolate_equidistant(T: VariableTypes, + T_base: float, + T_incr: float, + v_array: ValueTypes, + label: str) -> tuple[PropertyTypes, list[Assignment]]: + """ + Perform equidistant interpolation for symbolic or numeric temperature values. + + :param T: Temperature, either symbolic (sp.Symbol) or numeric (float). + :param T_base: Base temperature for the interpolation. + :param T_incr: Increment in temperature for each step in the interpolation array. + :param v_array: Array of values corresponding to the temperatures. + :param label: Label for the symbolic representation. + :return: Interpolated value and list of assignments (if symbolic). + :raises ValueError: If the temperature type is unsupported. + """ if isinstance(T, sp.Symbol): - data_base = sp.IndexedBase(label, shape=len(v_array)) - # idx = sp.symbols(label + '_idx', integer=True) - idx = sp.symbols(label + '_idx', cls=sp.Idx) - pos_dec = sp.Symbol("pos_dec") + sym_data = sp.IndexedBase(label, shape=len(v_array)) + sym_idx = sp.symbols(label + '_idx', cls=sp.Idx) + sym_dec = sp.Symbol("pos_dec") pos = (T - T_base) / T_incr - pos_int = sp.floor(pos) - # pos_dec = pos - pos_int # sp.frac(pos) not supported by pystencils yet! + pos_dec = pos - sp.floor(pos) # sp.frac(pos) not supported by pystencils yet! result = sp.Piecewise( (sp.Float(float(v_array[0])), T < T_base), (sp.Float(float(v_array[-1])), T >= T_base + (len(v_array) - 1) * T_incr), - ((1 - pos_dec) * data_base[idx] + pos_dec * data_base[idx + 1], True)) + ((1 - sym_dec) * sym_data[sym_idx] + sym_dec * sym_data[sym_idx + 1], True)) sub_expressions = [ - Assignment(data_base, tuple(sp.Float(float(v)) for v in v_array), "double[]"), - Assignment(idx, pos_int, "int"), - Assignment(pos_dec, pos - pos_int, "double") + Assignment(sym_data, tuple(sp.Float(float(v)) for v in v_array), "double[]"), + Assignment(sym_idx, pos, "int"), + Assignment(sym_dec, pos_dec, "double") ] return result, sub_expressions elif isinstance(T, float): @@ -44,7 +56,16 @@ def interpolate_equidistant(T: VariableTypes, T_base: float, T_incr: float, v_ar def interpolate_lookup(T: VariableTypes, T_array: ValueTypes, v_array: ValueTypes) -> PropertyTypes: - if len(T_array) != len(v_array): # Check if T_array and v_array have the same length + """ + Perform lookup interpolation for symbolic or numeric temperature values. + + :param T: Temperature, either symbolic (sp.Symbol) or numeric (float). + :param T_array: Array of temperature values. + :param v_array: Array of values corresponding to the temperatures. + :return: Interpolated value. + :raises ValueError: If the input arrays are of different lengths or the temperature type is unsupported. + """ + if len(T_array) != len(v_array): raise ValueError("T_array and v_array must have the same length") # assert len(T_array) == len(v_array), "T_array and v_array must have the same length" @@ -57,7 +78,7 @@ def interpolate_lookup(T: VariableTypes, T_array: ValueTypes, v_array: ValueType (v_array[-1], T >= T_array[-1])] for i in range(len(T_array) - 1): interp_expr = ( - v_array[i] + (v_array[i + 1] - v_array[i]) / (T_array[i + 1] - T_array[i]) * (T - T_array[i])) + v_array[i] + (v_array[i + 1] - v_array[i]) / (T_array[i + 1] - T_array[i]) * (T - T_array[i])) conditions.append( (interp_expr, sp.And(T >= T_array[i], T < T_array[i + 1]) if i + 1 < len(T_array) - 1 else True)) return sp.Piecewise(*conditions) @@ -67,6 +88,7 @@ def interpolate_lookup(T: VariableTypes, T_array: ValueTypes, v_array: ValueType if __name__ == '__main__': + # Example usage and consistency tests for the interpolation functions Temp = sp.Symbol('Temp') density_temp_array1 = np.array([200.0, 300.0, 400.0, 500.0, 600.0]) density_v_array1 = np.array([50.0, 40.0, 30.0, 20.0, 10.0]) diff --git a/src/materials/models.py b/src/materials/models.py index fb6908013a5101ecda23a93cb93fb69cad1b288a..d642945e52ba5371a2388fb5480a1df3d9782266 100644 --- a/src/materials/models.py +++ b/src/materials/models.py @@ -9,12 +9,19 @@ def density_by_thermal_expansion( thermal_expansion_coefficient: PropertyTypes) \ -> PropertyTypes: """ - Calculate density based on thermal expansion: rho_0 / (1 + tec * (T - T_0)) + Calculate density based on thermal expansion using the formula: + rho(T) = rho_0 / (1 + tec * (T - T_0))^3 - :param T: Temperature value. - :param base_temperature: Reference temperature. - :param base_density: Density at reference temperature. - :param thermal_expansion_coefficient: Thermal expansion coefficient. + Where: + - rho(T) is the density at temperature T. + - rho_0 is the density at the base temperature T_0. + - tec is the thermal expansion coefficient. + + :param T: Temperature value. Can be a numeric value (float) or a symbolic expression (sp.Symbol). + :param base_temperature: Reference temperature at which the base density is given, as a float. + :param base_density: Density at the reference temperature, as a float. + :param thermal_expansion_coefficient: Thermal expansion coefficient. Can be a numeric value (float) or a symbolic expression (sp.Expr). + :return: Density at temperature T. Returns a float if all inputs are numeric; otherwise, returns a sympy expression. """ return base_density / (1 + thermal_expansion_coefficient * (T - base_temperature)) ** 3 @@ -25,13 +32,22 @@ def thermal_diffusivity_by_heat_conductivity( heat_capacity: PropertyTypes) \ -> PropertyTypes: """ - Calculate thermal diffusivity: k(T) / (rho(T) * c_p(T)) + Calculate thermal diffusivity using the formula: + alpha(T) = k(T) / (rho(T) * c_p(T)) + + Where: + - alpha(T) is the thermal diffusivity at temperature T. + - k(T) is the thermal conductivity at temperature T. + - rho(T) is the density at temperature T. + - c_p(T) is the specific heat capacity at temperature T. - :param heat_conductivity: Thermal conductivity. - :param density: Density. - :param heat_capacity: Specific heat capacity. + :param heat_conductivity: Thermal conductivity. Can be a numeric value (float) or a symbolic expression (sp.Expr). + :param density: Density. Can be a numeric value (float) or a symbolic expression (sp.Expr). + :param heat_capacity: Specific heat capacity. Can be a numeric value (float) or a symbolic expression (sp.Expr). + :return: Thermal diffusivity. Returns a float if all inputs are numeric; otherwise, returns a sympy expression. """ result = heat_conductivity / (density * heat_capacity) - if isinstance(heat_conductivity, sp.Expr) or isinstance(density, sp.Expr) or isinstance(heat_capacity, sp.Expr): - result = sp.simplify(result) + # Optional: Simplify the result if any input is an expression (sp.Expr) + # if isinstance(heat_conductivity, sp.Expr) or isinstance(density, sp.Expr) or isinstance(heat_capacity, sp.Expr): + # result = sp.simplify(result) return result diff --git a/src/materials/typedefs.py b/src/materials/typedefs.py index 47f086164aec463886d16ba2dbc1e359b68384ee..3c84889263f2f025fa9f93791b802b6f688701a8 100644 --- a/src/materials/typedefs.py +++ b/src/materials/typedefs.py @@ -1,30 +1,52 @@ +""" +typedefs.py + +This module defines custom types and type aliases used throughout the materials module, enhancing +code readability and consistency. It includes data structures for assignments and mappings +between symbolic types and data types used in computations. + +Classes: + Assignment: A dataclass representing an assignment operation with a left-hand side (lhs), + right-hand side (rhs), and the type of the lhs. + +Type Aliases: + ValueTypes: A type alias for numerical data types, which can be either numpy arrays or lists of floats. + PropertyTypes: A type alias for properties that can be either constant floats or sympy expressions. + VariableTypes: A type alias for variables that can be either floats or sympy symbols. + AssignmentType: A type alias for a dictionary where keys are strings representing labels and values are lists of + `Assignment` objects associated with those labels. + +Functions: + type_mapping(type_str: str) -> Union[np.dtype, Arr]: + Maps a string representation of a type to a corresponding numpy or pystencils data type. +""" + import numpy as np import sympy as sp -from typing import Union +from typing import Union, Dict, List from dataclasses import dataclass -from pystencils.types.quick import * @dataclass class Assignment: + """ + Represents an assignment operation within the simulation. + + Attributes: + lhs (sp.Symbol): The left-hand side of the assignment, typically a symbolic variable. + rhs (Union[tuple, sp.Expr]): The right-hand side of the assignment, which can be a tuple or sympy expression. + lhs_type (str): The type of the left-hand side, indicating the data type. + """ lhs: sp.Symbol rhs: Union[tuple, sp.Expr] lhs_type: str -ValueTypes = np.ndarray | list[float] - -PropertyTypes = Union[float, sp.Expr] - -VariableTypes = Union[float, sp.Symbol] - -AssignmentType = dict[str, list[Assignment]] - +# Type aliases for various data types used in the project +ValueTypes = Union[np.ndarray, List[float]] # Numerical values can be represented as numpy arrays or lists of floats +PropertyTypes = Union[float, sp.Expr] # Property values can be either constant floats or sympy expressions +VariableTypes = Union[float, sp.Symbol] # Variables can be either numerical (floats) or symbolic (sympy symbols) -def type_mapping(type_str): - if type_str == "double[]": - return Arr(Fp(64)) - elif type_str == "float[]": - return Arr(Fp(32)) - else: - return np.dtype(type_str) +# Type alias for a dictionary of assignments +# Dictionary where keys are labels (strings) and values are lists of `Assignment` objects +AssignmentType = Dict[str, List[Assignment]]