Cross-referencing

In this tutorial, we’ll wire a model to its tensor inputs and to other models by name — the basic glue that lets an input file hold more than one object. Anywhere a field expects an object name, we can write the name of another section in the file.

Referring to a tensor from a model

When a model field expects a tensor value, we can point it at a [Tensors] entry by name:

[Tensors]
  [E]
    type = Python
    expr = 'Scalar(200e3)'
  []
  [nu]
    type = Python
    expr = 'Scalar(0.3)'
  []
[]

[Models]
  [elasticity]
    type = LinearIsotropicElasticity
    coefficients      = 'E              nu'                # ← refers to [Tensors] entries
    coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO'
  []
[]

But for simple scalar literals, many model fields accept the number directly — no [Tensors] section needed. (Non-scalar tensor inputs still need a [Tensors] entry.)

[Models]
  [elasticity]
    type = LinearIsotropicElasticity
    coefficients      = '200e3          0.3'               # inline literals
    coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO'
  []
[]

So when would we go through [Tensors]? When the literal won’t do — typically because we want to share the value across several models, or because it comes from a torch expression like torch.linspace(...) or a CSV file rather than a bare number.

Here’s a temperature-controls axis built from a torch expression:

[Tensors]
  [T_controls]
    type = Python
    expr = 'linspace(Scalar(300.0).sub_batch, Scalar(1200.0).sub_batch, 20)'
  []
[]

Once declared, every model that references T_controls shares it.

Referring to a model from another model

Some models operate on another model rather than on a tensor, and their model-valued field takes the name of a [Models] entry the same way. Normality is one: it differentiates a scalar-valued function produced by another model. Here it wraps the von Mises stress invariant to produce the associated flow direction \(\boldsymbol{N} = \partial \sigma_\mathrm{eff} / \partial \boldsymbol{\sigma}\):

[Models]
  [vonmises]
    type = SR2Invariant
    invariant_type = 'VONMISES'
    tensor    = 'mandel_stress'
    invariant = 'effective_stress'
  []
  [normality]
    type = Normality
    model    = 'vonmises'          # ← name of the [Models] entry above
    function = 'effective_stress'  # the scalar output of `vonmises` to differentiate
    from     = 'mandel_stress'
    to       = 'flow_direction'
  []
[]

model = 'vonmises' is the cross-reference: normality doesn’t redefine the invariant, it points at the existing [Models] entry by name and differentiates its effective_stress output. Note that function, from, and to are variable names, not section names — they pick out inputs and outputs by the variables a model produces and consumes, which is the wiring mechanism the next tutorial builds on.

Where to go next

The same name-binding mechanism is what ComposedModel uses to wire its children together — see Model composition.