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: 1regression for properties you intend to invertThe 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