Could not unroll graph- parameterized problem

When running a simple parameterized diffusion problem., the error message is:
"could not unroll graph!
This is probably because you are asking to compute a value that is not an output of any node"

the related source code is:
@modulus.main(config_path=“conf”, config_name=“config”)
def run(cfg: ModulusConfig) → None:

# make list of nodes to unroll graph on
diff_u1 = Diffusion(T="u_1", D="D1", dim=2, time=False)

diff_net_u_1 = instantiate_arch(
    input_keys=[Key("x"), Key("y"), **Key("D1")**],
    output_keys=[Key("u_1")],
    cfg=cfg.arch.fully_connected,
)

nodes = (
    diff_u1.make_nodes()
    + [diff_net_u_1.make_node(name="u1_network", jit=cfg.jit)]
)

Output:
####################################
invar: [x, y, sdf, area]
requested var: [u_1]
computable var: [x, y, sdf, area]
####################################
Nodes in graph:
node: Sympy Node: diffusion_u_1
evaluate: SympyToTorch
inputs: [D1]
derivatives: [D1__x, D1__y, u_1__x, u_1__x__x, u_1__y, u_1__y__y]
outputs: [diffusion_u_1]
optimize: False
node: Arch Node (jit): u1_network
evaluate: RecursiveScriptModule
inputs: [x, y, D1]
derivatives: []
outputs: [u_1]
optimize: True
####################################

the error is caused by the Key(“D1”) in the network input but not understood why?
A similar issue exists if I run the “diffusion_bar_parameterized.py” script from the examples

Hi @goutianos

This is likely because you are not supplying the variable D1 to your node. I would need to see your node declaration to comment further.

Have look at this post for some additional details on how to decipher these type of errors:

Thank you for the response. The full script is provided below showing the node declaration.


import torch
import numpy as np
from sympy import Symbol, Eq, Function, Number

import modulus
from modulus.hydra import to_absolute_path, ModulusConfig, instantiate_arch
from modulus.solver import Solver
from modulus.domain import Domain
from modulus.geometry.primitives_1d import Line1D
from modulus.geometry.primitives_2d import Rectangle
from modulus.geometry import Parameterization
from modulus.domain.constraint import (
PointwiseBoundaryConstraint,
PointwiseInteriorConstraint,
)
from modulus.domain.validator import PointwiseValidator
from modulus.domain.monitor import PointwiseMonitor
from modulus.domain.inferencer import PointwiseInferencer
from modulus.utils.io.plotter import ValidatorPlotter, InferencerPlotter
from modulus.key import Key
from modulus.node import Node
from modulus.eq.pde import PDE

#-------------------------------------
#Heat transfer (diffusion) partial differential equation
class Diffusion(PDE):
name = “Diffusion”

def __init__(self, T="T", D="D", Q=0, dim=3, time=True):
    # set params
    self.T = T
    self.dim = dim
    self.time = time

    # coordinates
    x, y, z = Symbol("x"), Symbol("y"), Symbol("z")

    # time
    t = Symbol("t")

    # make input variables
    input_variables = {"x": x, "y": y, "z": z, "t": t}
    if self.dim == 1:
        input_variables.pop("y")
        input_variables.pop("z")
    elif self.dim == 2:
        input_variables.pop("z")
    if not self.time:
        input_variables.pop("t")

    # Temperature
    assert type(T) == str, "T needs to be string"
    T = Function(T)(*input_variables)

    # Diffusivity
    if type(D) is str:
        D = Function(D)(*input_variables)
    elif type(D) in [float, int]:
        D = Number(D)

    # Source
    if type(Q) is str:
        Q = Function(Q)(*input_variables)
    elif type(Q) in [float, int]:
        Q = Number(Q)

    # set equations
    self.equations = {}
    self.equations["diffusion_" + self.T] = (
        T.diff(t)
        - (D * T.diff(x)).diff(x)
        - (D * T.diff(y)).diff(y)
        - (D * T.diff(z)).diff(z)
        - Q
    )

#-------------------------------------

parameters

#D1 = 10.0 # conductivity

Tc = 100.0
Ta = 0.0

create geometry - parameters for domain
domain_origin = (-0.5, -0.5)
domain_dim = (1, 1)

bounds

bounds_x = (domain_origin[0], domain_origin[0] + domain_dim[0])
bounds_y = (domain_origin[1], domain_origin[1] + domain_dim[1])

domain

square = Rectangle(domain_origin,
(domain_origin[0] + domain_dim[0], domain_origin[1] + domain_dim[1]),)

@modulus.main(config_path=“conf”, config_name=“config”)
def run(cfg: ModulusConfig) → None:

# make list of nodes to unroll graph on
diff_u1 = Diffusion(T="u_1", D="D1", dim=2, time=False)

diff_net_u_1 = instantiate_arch(
    input_keys=[Key("x"), Key("y"), Key("D1")],
    output_keys=[Key("u_1")],
    cfg=cfg.arch.fully_connected,
)

nodes = (
    diff_u1.make_nodes()
    + [diff_net_u_1.make_node(name="u1_network", jit=cfg.jit)]
)

# make domain add constraints to the solver
domain = Domain()

# sympy variables
x = Symbol("x")
y = Symbol("y")
D1 = Symbol("D1")
D1_range = {D1: (5, 25)} 


# right hand side (x = 5) Pt c
rhs = PointwiseBoundaryConstraint(
    nodes=nodes,
    geometry=square,
    outvar={"u_1": Tc},
    batch_size=cfg.batch_size.rhs,
    criteria=Eq(y, domain_origin[1]+ domain_dim[0]),
    parameterization=Parameterization(D1_range),
)
domain.add_constraint(rhs, "right_hand_side")

# left hand side (x = 0) Pt a
lhs = PointwiseBoundaryConstraint(
    nodes=nodes,
    geometry=square,
    outvar={"u_1": Ta},
    batch_size=cfg.batch_size.lhs,
    criteria=Eq(y, domain_origin[0]),
    parameterization=Parameterization(D1_range),
)
domain.add_constraint(lhs, "left_hand_side")

# interior 
interior_u1 = PointwiseInteriorConstraint(
    nodes=nodes,
    geometry=square,
    outvar={"diffusion_u_1": 0},
    bounds={x: bounds_x, y: bounds_y},
    batch_size=cfg.batch_size.interior_u1,
    parameterization=Parameterization(D1_range),
)
domain.add_constraint(interior_u1, "interior_u1")

# add inferencer data
inferencer = PointwiseInferencer(
    nodes=nodes,
    invar=square.sample_interior(
        2 * cfg.batch_size.interior_u1,
        bounds={x: bounds_x, y: bounds_y},
    ),
    output_names=["u_1"],
    batch_size=2048,
    plotter=InferencerPlotter(),
)
domain.add_inferencer(inferencer)

# make solver
slv = Solver(cfg, domain)

# start solver
slv.solve()

if name == “main”:
run()

I see the same issue when I solve 2D (dim=2) problems. If I switch to 3D geometries I don’t get this error.

My experience was with the ldc example and making the boundary condition for velocity a parametrized quantity.
This is how I changed the first few lines of that example
@modulus.sym.main(config_path="conf", config_name="config")
def run(cfg: ModulusConfig) -> None: ns = NavierStokes(nu=0.01, rho=1.0, dim=2, time=False) vel = Symbol("vel") flow_net = instantiate_arch( input_keys=[Key("x"), Key("y"), Key("vel")], output_keys=[Key("u"), Key("v"), Key("p")], cfg=cfg.arch.fully_connected, ) nodes = ns.make_nodes() + [flow_net.make_node(name="flow_network")]

height = 0.1
width = 0.1
x, y = Symbol("x"), Symbol("y")
rec = Rectangle((-width / 2, -height / 2), (width / 2, height / 2))

# make ldc domain
ldc_domain = Domain()

# top wall
top_wall = PointwiseBoundaryConstraint(
    nodes=nodes,
    geometry=rec,
    outvar={"u": vel, "v": 0},
    batch_size=cfg.batch_size.TopWall,
    lambda_weighting={"u": 1.0 - 20 * Abs(x), "v": 1.0},  # weight edges to be zero
    criteria=Eq(y, height / 2),
    parameterization=Parameterization({vel: 1.0})
)
ldc_domain.add_constraint(top_wall, "top_wall")

And the error

#################################### could not unroll graph! This is probably because you are asking to compute a value that is not an output of any node #################################### invar: [x, y, normal_x, normal_y, area] requested var: [u, v] computable var: [x, y, normal_x, normal_y, area, continuity] #################################### Nodes in graph: node: Sympy Node: continuity evaluate: SympyToTorch inputs: [] derivatives: [u__x, v__y] outputs: [continuity] optimize: False node: Sympy Node: momentum_x evaluate: SympyToTorch inputs: [u, v] derivatives: [p__x, u__x, u__x__x, u__y, u__y__y] outputs: [momentum_x] optimize: False node: Sympy Node: momentum_y evaluate: SympyToTorch inputs: [u, v] derivatives: [p__y, v__x, v__x__x, v__y, v__y__y] outputs: [momentum_y] optimize: False node: Arch Node: flow_network evaluate: FullyConnectedArch inputs: [x, y, vel] derivatives: [] outputs: [u, v, p] optimize: True ####################################

Any help would be appreciated.