Inverting Material Properties

This guide explains how to evaluate dependency-driven properties and create their inverse functions in MaterForge.

Why Property Inversion Matters

Material properties in MaterForge are expressed as dependency-driven symbolic functions. Sometimes you need to go in the reverse direction - given a property value, find the corresponding dependency value. Common examples:

  • Given energy density, find temperature

  • Given density, find the pressure at which it occurs

  • Given a measured property value, recover the driving variable

MaterForge supports this through PiecewiseInverter, which creates an inverse symbolic expression from any piecewise property.


Forward Evaluation

Given a material with a dependency-driven property, evaluate it at a specific value:

import sympy as sp
from materforge.parsing.api import create_material

T = sp.Symbol('T')   # any symbol works
mat = create_material('myAlloy.yaml', dependency=T)

# Evaluate all properties at T=1500
evaluated = mat.evaluate(T, 1500.0)
print(evaluated.energy_density)        # sp.Float
print(float(evaluated.energy_density)) # Python float if needed

# Or access the symbolic expression and substitute manually
expr = mat.energy_density              # SymPy Piecewise in T
value = float(expr.subs(T, 1500.0).evalf())

Inverse: From Property Value Back to Dependency

If your property is piecewise linear, PiecewiseInverter creates the inverse function as a new SymPy Piecewise expression:

import sympy as sp
from materforge.parsing.api import create_material
from materforge.algorithms.piecewise_inverter import PiecewiseInverter

T = sp.Symbol('T')
E = sp.Symbol('E')
mat = create_material('myAlloy.yaml', dependency=T)

# Create inverse: energy_density(T) -> T(E)
inverse = PiecewiseInverter.create_inverse(mat.energy_density, T, E)

# Evaluate: given energy density, recover temperature
energy_value = 1.5e9   # J/m^3
recovered_T = float(inverse.subs(E, energy_value))
print(f"Temperature at E={energy_value:.2e}: {recovered_T:.2f}")

input_symbol and output_symbol are the actual SymPy symbols used in the original expression and its inverse respectively

Round-Trip Validation

Always validate the inverse by checking the round-trip error:

test_values = [500.0, 800.0, 1200.0, 1500.0, 1800.0]

print(f"{'T_original':>12}  {'E':>14}  {'T_recovered':>12}  {'error':>10}")
print("-" * 55)
for t_orig in test_values:
    e = float(mat.energy_density.subs(T, t_orig).evalf())
    t_rec = float(inverse.subs(E, e))
    err = abs(t_rec - t_orig)
    print(f"{t_orig:>12.2f}  {e:>14.4e}  {t_rec:>12.4f}  {err:>10.2e}")

Using a Different Dependency Symbol

The workflow is identical regardless of what symbol drives the property:

import sympy as sp
from materforge.parsing.api import create_material
from materforge.algorithms.piecewise_inverter import PiecewiseInverter

P   = sp.Symbol('P')    # pressure-driven material
rho = sp.Symbol('rho')
mat = create_material('myMaterial.yaml', dependency=P)

inverse = PiecewiseInverter.create_inverse(mat.density, P, rho)

# Given a density value, recover pressure
target_density = 7200.0
pressure = float(inverse.subs(rho, target_density))

Known Limitation

PiecewiseInverter currently supports linear piecewise functions only. Properties with higher-degree polynomial segments (e.g. degree: 2 or higher in regression configuration) cannot be inverted automatically. Use degree: 1 in the regression block for any property you intend to invert:

energy_density:
    dependency: (300, 3000, 5.0)
    equation: density * specific_enthalpy
    bounds: [linear, linear]
    regression:
        simplify: pre
        degree: 1      # required for inversion
        segments: 6

Best Practices

  • Validate round-trip accuracy before using an inverse in production

  • Use degree: 1 regression for properties you intend to invert

  • The input property must be monotonic over its domain for the inverse to be well-defined - verify this by inspecting the forward plot

  • Prefer bounds: [linear, linear] for properties used in inversion so out-of-range queries degrade gracefully rather than clamping silently