Skip to main content

Simple Explicit Expressions with Subsystems

csdl supports constructing model hierarchies via the Model.add method. This example shows one way to define and add a model to the model hierarchy. The example starts by creating an input 'x1' to the main model (the model at the top of the model hierarchy). The variable 'x1' is created in the current scope, so any parent model cannot access 'x1' unless 'x1' is promoted to a higher level in the hierarchy. A new variable y4 in line 12 is defined in terms of x1. Note that y4 is the variable's name in Python, not CSDL. The corresponding name for y4 in CSDL is defined as 'y4' in line 45. If a variable is not registered with a CSDL name, then CSDL automatically names the variable. The Python name for a variable does not need to match its name in CSDL, but it is good practice to keep them consistent for readability.

In this example, 'subsystem' declares the variable 'x1', declaring an input to the model 'subsystem' from either a parent model, or a child model (in this case the parent model because 'subsystem' has no children). In the parent model, the create_input method creates an input 'x1' to the main model. The variable 'x1' belongs to the scope of ExampleWithSubsystems. output in the parent Model prior to the call to Model.add in order to update the input values in 'sys'.

promotes on line 22

In this case, there is an input to the main model named 'x1' in the main model, so when 'subsystem' is promoted, the declared variable 'x1' can be referenced as 'x1' instead of 'subsystem.x1' after line 48.

Likewise, if the parent Model is to use an output registered in 'subsystem', such as 'x2', then the user must call Model.declare_variable after Model.add for that variable.

from csdl_om import Simulatorfrom csdl import Model, NonlinearBlockGSimport csdlimport numpy as np

class ExampleWithSubsystems(Model):
    def define(self):        # Create input to main model        x1 = self.create_input('x1', val=40)
        # Powers        y4 = x1**2
        # Create subsystem that depends on previously created        # input to main model        m = Model()
        # This value is overwritten by connection from the main model        a = m.declare_variable('x1', val=2)        b = m.create_input('x2', val=12)        m.register_output('prod', a * b)        self.add(m, name='subsystem')
        # declare inputs with default values        # This value is overwritten by connection        # from the submodel        x2 = self.declare_variable('x2', val=3)
        # Simple addition        y1 = x2 + x1        self.register_output('y1', y1)
        # Simple subtraction        self.register_output('y2', x2 - x1)
        # Simple multitplication        self.register_output('y3', x1 * x2)
        # Powers        y5 = x2**2
        # register outputs in reverse order to how they are defined        self.register_output('y5', y5)        self.register_output('y6', y1 + y5)        self.register_output('y4', y4)

sim = Simulator(ExampleWithSubsystems())sim.run()
print('prod', sim['prod'].shape)print(sim['prod'])print('y1', sim['y1'].shape)print(sim['y1'])print('y2', sim['y2'].shape)print(sim['y2'])print('y3', sim['y3'].shape)print(sim['y3'])print('y4', sim['y4'].shape)print(sim['y4'])print('y5', sim['y5'].shape)print(sim['y5'])print('y6', sim['y6'].shape)print(sim['y6'])
[480.]y1 (1,)[52.]y2 (1,)[-28.]y3 (1,)[480.]y4 (1,)[1600.]y5 (1,)[144.]y6 (1,)[196.]