# Defining Custom Material Properties This guide explains how to define custom material properties in MaterForge using different property types. ## Overview MaterForge uses a schema-agnostic YAML format - any material kind (metals, alloys, polymers, ceramics, composites, or hypothetical materials) and any property name are valid. Properties can be constants or expressions driven by any independent variable (temperature, pressure, composition, strain, or any SymPy symbol). SI units are recommended throughout. ## YAML Configuration Options ### 1. Constant Value For properties that do not vary with the dependency variable: ```yaml properties: thermal_expansion_coefficient: 16.3e-6 density: 7000.0 ``` ### 2. Step Functions For properties that change abruptly at a transition point: ```yaml properties: latent_heat_of_fusion: dependency: solidus_temp + 5 # reference to another scalar property value: [0.0, 171401.0] # [before_transition, after_transition] bounds: [constant, constant] ``` `dependency` here is a single scalar reference or arithmetic expression that defines the transition point. ### 3. Importing from External Files For properties defined in spreadsheets or data files: ```yaml properties: # Excel file import density: file_path: ./material_data.xlsx dependency_column: T (K) property_column: Density (kg/m^3) bounds: [constant, constant] # CSV file import heat_capacity: file_path: ./heat_capacity_data.csv dependency_column: Temperature property_column: Cp bounds: [constant, constant] # Text file import (space/tab separated, headerless - use column index) thermal_conductivity: file_path: ./conductivity_data.txt dependency_column: 0 property_column: 1 bounds: [constant, constant] ``` Supported formats: `.txt` (space/tab separated), `.csv`, `.xlsx`. ### 4. Tabular Data For properties defined by paired dependency-value lists: ```yaml properties: heat_conductivity: dependency: [500, 1000, 1600, 1700, 1750, 2000, 2500] value: [19.25, 25.47, 32.94, 33.52, 31.53, 35.33, 42.95] bounds: [constant, constant] # Using scalar property references in the dependency list latent_heat_of_fusion: dependency: [solidus_temp - 1, liquidus_temp + 1] value: [0, 171401.0] bounds: [constant, constant] # Using tuple notation density: dependency: (1735.0, -5) # start=1735, decrement by 5 per value value: [7037.47, 7060.15, 7088.80, 7110.46, 7127.68] bounds: [constant, constant] ``` ### 5. Piecewise Equations For properties with different expressions over different ranges: ```yaml properties: viscosity: dependency: [300, 1660, 1736, 3000] # n breakpoints -> n-1 equations equation: [7877.39-0.37*T, 11816.63-2.74*T, 8596.40-0.88*T] bounds: [constant, constant] ``` The symbol in the equation (`T` here) is just a placeholder. It is replaced by the symbol passed to `create_material(..., dependency=X)` at runtime. The symbol used in equations (`T` in the example above) is a placeholder only. So this is valid: ```python P = sp.Symbol('P') mat = create_material('myAlloy.yaml', dependency=P) print(mat.viscosity) # Piecewise in P, not T ``` The YAML file never needs to change regardless of what symbol the caller uses. ### 6. Computed Properties For properties derived from other already-defined properties: ```yaml properties: thermal_diffusivity: dependency: (3000, 300, -5.0) equation: heat_conductivity / (density * heat_capacity) bounds: [linear, linear] regression: simplify: post degree: 2 segments: 3 ``` MaterForge resolves property dependencies automatically - `thermal_diffusivity` will always be processed after `heat_conductivity`, `density`, and `heat_capacity` regardless of their order in the YAML file. --- ## Dependency Definition Formats The `dependency` key accepts five formats: ```yaml # 1. Explicit list of values dependency: [300, 500, 800, 1000] # 2. Tuple (start, increment) - length inferred from value list dependency: (300, 50) # 300, 350, 400, ... # 3. Tuple (start, stop, step) - step is float dependency: (300, 1000, 10.0) # 300, 310, 320, ..., 1000 # 4. Tuple (start, stop, points) - points is integer dependency: (300, 1000, 71) # 71 evenly spaced values # 5. Decreasing range dependency: (1000, 300, -5.0) # 1000, 995, 990, ..., 300 ``` Scalar property references and arithmetic expressions are also valid inside lists: ```yaml dependency: [solidus_temp - 1, liquidus_temp + 1] dependency: solidus_temp + 5 # single reference for step functions ``` --- ## Bounds Options Controls behaviour outside the defined range: ```yaml bounds: [constant, linear] ``` | Option | Behaviour | |-------------|--------------------------------------------------| | constant | Clamp to the boundary value outside the range | | linear | Linear extrapolation beyond the range | --- ## Regression Configuration Reduces expression complexity and smooths noisy data: ```yaml regression: simplify: pre # 'pre': applied to raw data before symbolic processing # 'post': applied after symbolic expressions are evaluated degree: 1 # polynomial degree per segment (1=linear, 2=quadratic, ...) segments: 3 # number of piecewise segments (<=8 recommended) ``` Note: High segment counts (>6) risk overfitting. MaterForge will warn if this threshold is exceeded. --- ## Complete Example ```yaml name: "myAlloy" properties: density: 7000.0 solidus_temp: 1605. liquidus_temp: 1735. latent_heat_of_fusion: dependency: solidus_temp + 5 value: [0.0, 171401.0] bounds: [constant, constant] heat_conductivity: dependency: [500, 1000, 1600, 1700, 1750, 2000, 2500] value: [19.25, 25.47, 32.94, 33.52, 31.53, 35.33, 42.95] bounds: [linear, linear] heat_capacity: file_path: ./myAlloy.csv dependency_column: T (K) property_column: Specific heat (J/(Kg K)) bounds: [constant, constant] regression: simplify: pre degree: 3 segments: 6 viscosity: dependency: [300, 1660, 1736, 3000] equation: [7877.39-0.37*T, 11816.63-2.74*T, 8596.40-0.88*T] bounds: [constant, constant] thermal_diffusivity: dependency: (3000, 300, -5.0) equation: heat_conductivity / (density * heat_capacity) bounds: [linear, linear] regression: simplify: post degree: 3 segments: 7 ``` Load it in Python: ```python import sympy as sp from materforge.parsing.api import create_material T = sp.Symbol('T') # any symbol works: sp.Symbol('P'), sp.Symbol('x'), etc. mat = create_material('myAlloy.yaml', dependency=T, enable_plotting=True) # Access symbolic expressions directly print(mat.heat_conductivity) # SymPy Piecewise expression in T print(mat.density) # 7000.0 (constant float) # Evaluate all properties at a specific value evaluated = mat.evaluate(T, 500.0) print(evaluated.heat_conductivity) # sp.Float, prints as number e.g. 25.47 print(float(evaluated.heat_conductivity)) # Python float if downstream code requires i ``` --- ## Best Practices - Use SI units throughout and document units in comments - Cover the full range of your dependency variable in tabular and piecewise data - Validate property values against experimental data where possible - All numeric values must use '.' as the decimal separator, not ',' - Interpolation between data points is automatic for tabular and file-import properties - Keep regression segments <= 8; prefer simplify: post for computed properties