# 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. The only required top-level fields are `name` and `properties`. Everything else is driven by what you put in the `properties` block. Properties can be constants or dependency-driven expressions. The independent variable can be any SymPy symbol - temperature, pressure, composition fraction, strain, or anything else. The symbol `T` used in YAML equations is a placeholder only; MaterForge substitutes it with whatever symbol you pass to `create_material(..., dependency=symbol)` at runtime. 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 # scalar property reference with arithmetic 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. The referenced property (e.g. `solidus_temp`) must be defined as a constant elsewhere in the `properties` block. ### 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: # Explicit list 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] # 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] # Tuple: (start, increment) - length inferred from value list heat_capacity: dependency: (273.15, 100.0) value: [897, 921, 950, 980, 1010, 1040, 1070, 1084] bounds: [constant, constant] # Tuple with negative increment density: dependency: (1735.0, -5) 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 of the dependency variable. `n` breakpoints define `n-1` equations: ```yaml properties: 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] ``` `T` in equations is a placeholder. MaterForge replaces it with the symbol passed to `create_material(..., dependency=symbol)` at runtime - the final expressions use your symbol. ### 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 energy_density: dependency: (300, 3000, 541) equation: density * specific_enthalpy bounds: [linear, linear] ``` MaterForge resolves property dependencies automatically - `thermal_diffusivity` is always processed after `heat_conductivity`, `density`, and `heat_capacity` regardless of their order in the file. --- ## Dependency Definition Formats The `dependency` key accepts five formats: ```yaml # 1. Explicit list 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 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 data range: ```yaml bounds: [constant, linear] ``` | Option | Behaviour | |-------------|------------------------------------------------| | constant | Clamp to the boundary value outside the range | | linear | Linear extrapolation beyond the range | --- ## Regression Configuration Optional. 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 # Minimal required structure: name + properties block name: "myAlloy" properties: # Scalar constants - referenced by other properties density: 7000.0 solidus_temp: 1605. liquidus_temp: 1735. # Step function referencing a scalar property latent_heat_of_fusion: dependency: solidus_temp + 5 value: [0.0, 171401.0] bounds: [constant, constant] # Tabular data 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] # File import with regression 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 # Piecewise equations (T is a placeholder, replaced at runtime) 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] # Computed property 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 # Any symbol works - T, P, x, or anything else T = sp.Symbol('T') 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 print(float(evaluated.heat_conductivity)) # Python float if needed ``` --- ## 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 - Dependency arrays must be monotonic for interpolation to work correctly - Computed properties are resolved in dependency order automatically - no manual ordering needed --- ## Important Notes - A property cannot be defined more than once in the same file - All dependencies of a computed property must be defined in the same `properties` block - The `T` placeholder in equations has no significance beyond being a valid SymPy symbol name; it is substituted at runtime with the caller-supplied symbol - `bounds` is required for all non-constant property types