Skip to main content

Developer API


csdl.core.model

ImplicitOperationFactory Objects#

class ImplicitOperationFactory(object)

__init__#

def __init__(parent, model)

declare_state#

def declare_state(state: str, bracket: Tuple[Union[int, float, np.ndarray],                       Union[int, float, np.ndarray]] = None, val=1.0, units=None, desc='', tags=None, shape_by_conn=False, copy_shape=None, distributed=None, res_units=None, lower=None, upper=None, ref=1.0, ref0=0.0, res_ref=1.0, *, residual: str)

__call__#

def __call__(*arguments: Variable, *, expose: List[str] = [], defaults: Dict[str, Union[int, float, np.ndarray]] = dict())

build_symbol_table#

def build_symbol_table(symbol_table, node)

_run_front_end_and_middle_end#

def _run_front_end_and_middle_end(run_front_end: Callable) -> Callable

Run CSDL compiler front end (Model.define) and middle end. The middle end is run immediately after the front end automatically. Model inherits from the metaclass _CompilerFrontEndMiddleEnd. The metaclass _CompilerFrontEndMiddleEnd replaces the Model.define method with this function, which calls Model.define and then performs the functions of the CSDL compiler middle end. The user does not need to opt into running the middle end and cannot opt out of running the middle end.

_CompilerFrontEndMiddleEnd Objects#

class _CompilerFrontEndMiddleEnd(type)

__new__#

def __new__(cls, name, bases, attr)

Model Objects#

class Model(, metaclass=_CompilerFrontEndMiddleEnd)

__init__#

def __init__(**kwargs)

optimize_ir#

def optimize_ir(flag: bool = True)

initialize#

def initialize()

User defined method to declare parameter values. Parameters are compile time constants (neither inputs nor outputs to the model) and cannot be updated at runtime. Parameters are intended to make a Model subclass definition generic, and therefore reusable. The example below shows how a Model subclass definition uses parameters and how the user can set parameters when constructing the example Model subclass.

Example

class Example(Model):    def initialize(self):        self.parameters.declare('num_times', types=int)        self.parameters.declare('step_size', types=float)        self.parameters.declare('surface', types=dict)
    def define(self):        num_times = self.parameters['num_times']        step_size = self.parameters['step_size']        surface = self.parameters['surface']        name = surface['name'] # str        symmetry = surface['symmetry'] # bool        mesh = surface['mesh'] # numpy array
        # define runtime behavior...
    surface = {        'name': 'wing',        'symmetry': False,        'mesh': mesh,    }
    # compile using Simulator imported from back end...    sim = Simulator(        Example(            num_times=100,            step_size=0.1,            surface=surface,        ),    )

define#

def define()

User defined method to define runtime behavior. Note: the user never calls this method. Only the Simulator class constructor calls this method.

Example

class Example(Model):    def define(self):        self.create_input('x')        m = 5        b = 3        y = m*x + b        self.register_output('y', y)
# compile using Simulator imported from back end...sim = Simulator(Example())sim['x'] = -3/5sim.run()print(sim['y']) # expect 0

_redefine#

def _redefine(expose: List[str])

Remove edges so that we can update the graph. This is only used when exposing intermediate variables for a composite residual.

print_var#

def print_var(var: Variable)

Print runtime value during execution. Note that print_var should only be used for debugging, as it does have a performance impact. Note that Python's print function will print the CSDL compile time Variable object information, and will have no effect on run time execution.

Example

y = csdl.sin(x)print(y) # will print compile time information about yself.print_var(y) # will print run time value of y

add_objective#

def add_objective(name, ref=None, ref0=None, index=None, units=None, adder=None, scaler=None, parallel_deriv_color=None, cache_linear_solution=False)

Declare the objective for the optimization problem. Objective must be a scalar variable.

add_design_variable#

def add_design_variable(name, lower=None, upper=None, ref=None, ref0=None, indices=None, adder=None, scaler=None, units=None, parallel_deriv_color=None, cache_linear_solution=False)

Add a design variable to the optimization problem. The design variable must be an Input. This will signal to the optimizer that it is responsible for updating the input variable.

add_constraint#

def add_constraint(name, lower=None, upper=None, equals=None, ref=None, ref0=None, adder=None, scaler=None, units=None, indices=None, linear=False, parallel_deriv_color=None, cache_linear_solution=False)

Add a constraint to the optimization problem.

connect#

def connect(a: str, b: str)

declare_variable#

def declare_variable(name: str, val=1.0, shape=(1, ), src_indices=None, flat_src_indices=None, units=None, desc='', tags=None, shape_by_conn=False, copy_shape=None, distributed=None) -> DeclaredVariable

Declare an input to use in an expression.

An input can be an output of a child System. If the user declares an input that is computed by a child System, then the call to self.declare_variable must appear after the call to self.add.

Parameters

name: str Name of variable in CSDL to be used as a local input that takes a value from a parent model, child model, or previously registered output within the model. shape: Tuple[int] Shape of variable val: Number or ndarray Default value for variable

Returns

DocInput An object to use in expressions

create_input#

def create_input(name, val=1.0, shape=(1, ), units=None, desc='', tags=None, shape_by_conn=False, copy_shape=None, distributed=None) -> Input

Create an input to the main model, whose value remains constant during model evaluation.

Parameters

name: str Name of variable in CSDL shape: Tuple[int] Shape of variable val: Number or ndarray Value for variable during first model evaluation

Returns

Input An object to use in expressions

create_output#

def create_output(name, val=1.0, shape=(1, ), units=None, res_units=None, desc='', lower=None, upper=None, ref=1.0, ref0=0.0, res_ref=1.0, tags=None, shape_by_conn=False, copy_shape=None, distributed=None) -> Concatenation

Create a value that is computed explicitly, either through indexed assignment, or as a fixed point iteration.

Example

x = self.create_output('x', shape=(5,3,2))x[:, :, 0] = ax[:, :, 1] = b

Parameters

name: str Name of variable in CSDL shape: Tuple[int] Shape of variable

Returns

Concatenation An object to use in expressions

register_output#

def register_output(name: str, var: Output) -> Output

Register var as an output of the Model. When adding subsystems, each of the submodel's inputs requires a call to register_output prior to the call to add.

Parameters

name: str

Name of variable in CSDL

var: Output

Variable that defines output

Returns

Output

Variable that defines output (same object as argument)

add#

def add(submodel, name: str = '', promotes: List[str] = None)

Add a submodel to the Model.

self.add call must be preceded by a call to self.register_output for each of the submodel's inputs, and followed by self.declare_variable for each of the submodel's outputs.

Parameters

name: str Name of submodel submodel: System Subsystem to add to Model promotes: List Variables to promote

Returns

System Subsystem to add to Model

_bracketed_search#

def _bracketed_search(implicit_metadata: Dict[str, dict], *arguments: Variable, *, states: List[str], residuals: List[str], model, brackets: Dict[str, Tuple[Union[int, float, np.ndarray],                                  Union[int, float, np.ndarray]]], expose: List[str] = [], maxiter: int = 100)

Create an implicit operation whose residuals are defined by a Model. An implicit operation is an operation that solves an equation f(x,y)=0f(x,y)=0 for yy, given some value of xx. CSDL solves f(x,y)=0f(x,y)=0 by defining a residual r=f(x,y)r=f(x,y) and updating yy until rr converges to zero.

Parameters

arguments: List[Variable]

List of variables to use as arguments for the implicit operation. Variables must have the same name as a declared variable within the model's class definition.

note

The declared variable must be declared within model and not promoted from a child submodel.

states: List[str]

Names of states to compute using the implicit operation. The order of the names of these states corresponds to the order of the output variables returned by implicit_operation. The order of the names in states must also match the order of the names of the residuals associated with each state in residuals.

note

The declared variable must be declared within model and not promoted from a child submodel.

residuals: List[str]

The residuals associated with the states. The name of each residual must match the name of a registered output in model.

note

The registered output must be registered within model and not promoted from a child submodel.

model: Model

The Model object to use to define the residuals. Residuals may be defined via functional composition and/or hierarchical composition.

note

Any Model object may be used to define residuals for an implicit operation

nonlinear_solver: NonlinearSolver

The nonlinear solver to use to converge the residuals

linear_solver: LinearSolver

The linear solver to use to solve the linear system

expose: List[str]

List of intermediate variables inside model that are required for computing residuals to which it is desirable to have access outside of the implicit operation. For example, if a trajectory is computed using time marching and a residual is computed from the final state of the trajectory, it may be desirable to plot that trajectory after the conclusion of a simulation, e.g. after an iteration during an optimization process.

note

The variable names in expose may be any name within the model hierarchy defined in model, but the variable names in expose are neither declared variables, nor registered outputs in model, although they may be declared variables/registered outputs in a submodel (i.e. they are neither states nor residuals in the, implicit operation).

Returns

Tuple[Ouput]

Variables to use in this Model. The variables are named according to states and expose, and are returned in the same order in which they are declared. For example, if states=['a', 'b', 'c'] and expose=['d', 'e', 'f'], then the outputs a, b, c, d, e, f in a, b, c, d, e, f = self.implcit_output(...) will be named 'a', 'b', 'c', 'd', 'e', 'f', respectively. This enables use of exposed intermediate variables (in addition to the states computed by converging the residuals) from model in this Model. Unused outputs will be ignored, so a, b, c = self.implcit_output(...) will make the variables declared in expose available for recording/analysis and promotion/connection, but they will be unused by this Model. Note that these variables are already registered as outputs in this Model, so there is no need to call Model.register_output for any of these variables.

_implicit_operation#

def _implicit_operation(implicit_metadata: Dict[str, dict], *arguments: Variable, *, states: List[str], residuals: List[str], model, nonlinear_solver: NonlinearSolver, linear_solver: LinearSolver = None, expose: List[str] = [], defaults: Dict[str, Union[int, float, np.ndarray]] = dict()) -> Tuple[Output, ...]

Create an implicit operation whose residuals are defined by a Model. An implicit operation is an operation that solves an equation f(x,y)=0f(x,y)=0 for yy, given some value of xx. CSDL solves f(x,y)=0f(x,y)=0 by defining a residual r=f(x,y)r=f(x,y) and updating yy until rr converges to zero.

Parameters

arguments: List[Variable]

List of variables to use as arguments for the implicitoperation.Variables must have the same name as a declared variablewithin the `model`'s class definition.
:::noteThe declared variable _must_ be declared within `model`_and not_ promoted from a child submodel.:::

states: List[str]

Names of states to compute using the implicit operation.The order of the names of these states corresponds to theorder of the output variables returned by`implicit_operation`.The order of the names in `states` must also match the orderof the names of the residuals associated with each state in`residuals`.
:::noteThe declared variable _must_ be declared within `model`_and not_ promoted from a child submodel.:::

residuals: List[str]

The residuals associated with the states.The name of each residual must match the name of aregistered output in `model`.
:::noteThe registered output _must_ be registered within `model`_and not_ promoted from a child submodel.:::

model: Model

The `Model` object to use to define the residuals.Residuals may be defined via functional composition and/orhierarchical composition.
:::note_Any_ `Model` object may be used to define residuals for animplicit operation:::

nonlinear_solver: NonlinearSolver

The nonlinear solver to use to converge the residuals

linear_solver: LinearSolver

The linear solver to use to solve the linear system

expose: List[str]

List of intermediate variables inside `model` that arerequired for computing residuals to which it is desirableto have access outside of the implicit operation.
For example, if a trajectory is computed using time marchingand a residual is computed from the final state of thetrajectory, it may be desirable to plot that trajectoryafter the conclusion of a simulation, e.g. after aniteration during an optimization process.
:::noteThe variable names in `expose` may be any name within themodel hierarchy defined in `model`, but the variable namesin `expose` are neither declared variables, nor registeredoutputs in `model`, although they may be declaredvariables/registered outputs in a submodel (i.e. they areneither states nor residuals in the, implicit operation).:::

Returns

Tuple[Ouput]

Variables to use in this `Model`.The variables are named according to `states` and `expose`,and are returned in the same order in which they aredeclared.For example, if `states=['a', 'b', 'c']` and`expose=['d', 'e', 'f']`, then the outputs`a, b, c, d, e, f` in`a, b, c, d, e, f = self.implcit_output(...)`will be named`'a', 'b', 'c', 'd', 'e', 'f'`, respectively.This enables use of exposed intermediate variables (inaddition to the states computed by converging theresiduals) from `model` in this `Model`.Unused outputs will be ignored, so`a, b, c = self.implcit_output(...)`will make the variables declared in `expose` available forrecording/analysis and promotion/connection, but they willbe unused by this `Model`.Note that these variables are already registered as outputsin this `Model`, so there is no need to call`Model.register_output` for any of these variables.

_something#

def _something(model, arguments, states, residuals, expose: List[str] = [])

_return_implicit_outputs#

def _return_implicit_outputs(model, op: ImplicitOperation, arguments: Tuple[Variable, ...], states: List[str], residuals: List[str], expose: List[str], implicit_metadata: Dict[str, dict]) -> Tuple[Output, ...]

create_implicit_operation#

def create_implicit_operation(model)

__enter__#

def __enter__()

__exit__#

def __exit__(type, value, traceback)

create_submodel#

@contextmanagerdef create_submodel(name: str)

Create a Model object and add as a submodel, promoting all inputs and outputs. For use in with contexts. NOTE: Only use if planning to promote all varaibales within child Model object.

Parameters

name: str Name of new child Model object

Returns

Model Child Model object whose variables are all promoted

visualize_sparsity#

def visualize_sparsity()

Visualize the sparsity pattern of jacobian for this model

visualize_graph#

def visualize_graph()

add_diag_implicit#

def add_diag_implicit(A, variables, implicit_outputs, indices=dict(), implicit_nodes=dict(), p=0, indent='')

add_off_diag_implicit#

def add_off_diag_implicit(A, indices, implicit_nodes)

add_diag#

def add_diag(A, nodes, indices=dict(), implicit_nodes=dict(), p=0, indent='')

add_off_diag#

def add_off_diag(A, model, indices)

csdl.core.simulator_base

_ReprClass Objects#

class _ReprClass(object)

Class for defining objects with a simple constant string repr.

This is useful for constants used in arg lists when you want them to appear in automatically generated source documentation as a certain string instead of python's default representation.

__init__#

def __init__(repr_string)

Inititialize the repr string.

Parameters

repr_string : str The string to be returned by repr

__repr__#

def __repr__()

Return our _repr_string.

Returns

str Whatever string we were initialized with.

SimulatorBase Objects#

class SimulatorBase()

A class that can be used as a base class for the Simulator class that a CSDL compiler back end would provide. This class is only here so that CSDL users and CSDL compiler back end developers have API documentation. CSDL users are not to use the SimulatorBase class provided by csdl, only the Simulator class provided by the CSDL compiler back end of choice.

__init__#

def __init__(model, reorder=False)

Constructor.

__getitem__#

def __getitem__(key) -> np.ndarray

Method to get variable values before or after a simulation run

__setitem__#

def __setitem__(key, val)

Method to set values for variables by name

run#

def run()

Method to run a simulation once. This method should be implemented so that it can be called repeatedly to solve an optimization problem.

compute_total_derivatives#

def compute_total_derivatives(return_format='array') -> Union[OrderedDict, np.ndarray]

Method to compute total derivatives (objective gradient and constraint jacobian)

Returns

Union[OrderedDict, np.ndarray]`

compute_exact_hessian#

def compute_exact_hessian()

Method to compute exact Hessian

check_partials#

def check_partials()

Method to compute the error for all partial derivatives of all operations within the model.

Returns

An object that is compatible with assert_check_partials

assert_check_partials#

def assert_check_partials(result, atol=1e-8, rtol=1e-8)

Method to check that the partial derivatives of all operations are within a specified tolerance.

Parameters

result: Return type of check_partials

visualize_implementation#

def visualize_implementation()

A method for the back end to provide its own visualization of the model.

get_design_variable_metadata#

def get_design_variable_metadata() -> dict

Method to get design variable metadata that an optimizer needs to define an optimization problem

Returns

`dict`

get_constraints_metadata#

def get_constraints_metadata() -> OrderedDict

Method to get constraint metadata that an optimizer needs to define an optimization problem

Returns

`OrderedDict`

update_design_variables#

def update_design_variables(x: np.ndarray, input_format='array')

Method for external optimizer to update design variable values

design_variables#

def design_variables(return_format='array') -> Union[OrderedDict, np.ndarray]

Method to provide optimizer with design variables Returns

`Union[OrderedDict, np.ndarray]`

objective#

def objective() -> float

Method to provide optimizer with objective

constraints#

def constraints(return_format='array') -> Union[OrderedDict, np.ndarray]

Method to provide optimizer with constraints

Returns

`Union[OrderedDict, np.ndarray]`

implicit_outputs#

def implicit_outputs()

Method to provide optimizer with implicit_outputs

residuals#

def residuals() -> Union[OrderedDict, np.ndarray]

Method to provide optimizer with residuals

objective_gradient#

def objective_gradient() -> Union[OrderedDict, np.ndarray]

Method to provide optimizer with total derivative of objective with respect to design variables; does not compute derivatives; must call Simulator.compute_total_derivatives to compute derivatives

Returns

`Union[OrderedDict, np.ndarray]`

constraint_jacobian#

def constraint_jacobian() -> Union[OrderedDict, np.ndarray]

Method to provide optimizer with total derivative of constraints with respect to design variables; does not compute derivatives; must call Simulator.compute_total_derivatives to compute derivatives

Returns

`Union[OrderedDict, np.ndarray]`

residuals_jacobian#

def residuals_jacobian() -> Union[OrderedDict, np.ndarray]

Method to provide optimizer with total derivatives of residuals with respect to design variables

csdl.core.custom_explicit_operation

CustomExplicitOperation Objects#

class CustomExplicitOperation(CustomOperation)

compute#

def compute(inputs, outputs)

Define outputs as an explicit function of the inputs

Example

def compute(self, inputs, outputs):    outputs['L'] = 1/2 * inputs['Cl'] * inputs['rho'] * inputs['V']**2 * inputs['S']    outputs['D'] = 1/2 * inputs['Cd'] * inputs['rho'] * inputs['V']**2 * inputs['S']

compute_derivatives#

def compute_derivatives(inputs, derivatives)

User defined method to compute partial derivatives for this operation

Example

def compute(self, inputs, outputs):    outputs['L'] = 1/2 * inputs['Cl'] * inputs['rho'] * inputs['V']**2 * inputs['S']    outputs['D'] = 1/2 * inputs['Cd'] * inputs['rho'] * inputs['V']**2 * inputs['S']
def compute_derivatives(self, inputs, derivatives):    derivatives['L', 'Cl'] = 1/2 * inputs['rho'] * inputs['V']**2 * inputs['S']    derivatives['L', 'rho'] = 1/2 * inputs['Cl'] * inputs['V']**2 * inputs['S']    derivatives['L', 'V'] = inputs['Cl'] * inputs['rho'] * inputs['V'] * inputs['S']    derivatives['L', 'S'] = 1/2 * inputs['Cl'] * inputs['rho'] * inputs['V']**2
    derivatives['D', 'Cd'] = 1/2 * inputs['rho'] * inputs['V']**2 * inputs['S']    derivatives['D', 'rho'] = 1/2 * inputs['Cd'] * inputs['V']**2 * inputs['S']    derivatives['D', 'V'] = inputs['Cd'] * inputs['rho'] * inputs['V'] * inputs['S']    derivatives['D', 'S'] = 1/2 * inputs['Cd'] * inputs['rho'] * inputs['V']**2

compute_jacvec_product#

def compute_jacvec_product(inputs, d_inputs, d_outputs, mode)

[Optional] Implement partial derivatives by computing a matrix-vector product

Example

def compute(self, inputs, outputs):    outputs['area'] = inputs['length'] * inputs['width']
def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode):    if mode == 'fwd':        if 'area' in d_outputs:            if 'length' in d_inputs:                d_outputs['area'] += inputs['width'] * d_inputs['length']            if 'width' in d_inputs:                d_outputs['area'] += inputs['length'] * d_inputs['width']    elif mode == 'rev':        if 'area' in d_outputs:            if 'length' in d_inputs:                d_inputs['length'] += inputs['width'] * d_outputs['area']            if 'width' in d_inputs:                d_inputs['width'] += inputs['length'] * d_outputs['area']

csdl.core.custom_implicit_operation

CustomImplicitOperation Objects#

class CustomImplicitOperation(CustomOperation)

__init__#

def __init__(*args, **kwargs)

evaluate_residuals#

def evaluate_residuals(inputs, outputs, residuals)

User defined method to evaluate residuals

Example

.. code-block:: python

def evaluate_residuals(self, inputs, outputs, residuals):    x = outputs['x']    a = inputs['a']    b = inputs['b']    c = inputs['c']    residuals['x'] = a * x**2 + b * x + c

compute_derivatives#

def compute_derivatives(inputs, outputs, derivatives)

[Optional] User defined method to evaluate exact derivatives of residuals wrt inputs and outputs

Example

.. code-block:: python

def compute_derivatives(self, inputs, outputs, derivatives):    a = inputs['a']    b = inputs['b']    x = outputs['x']
    derivatives['x', 'a'] = x**2    derivatives['x', 'b'] = x    derivatives['x', 'c'] = 1.0    derivatives['x', 'x'] = 2 * a * x + b
    # only necessary if implementing `apply_inverse_jacobian`    self.inv_jac = 1.0 / (2 * a * x + b)

solve_residual_equations#

def solve_residual_equations(inputs, outputs)

[Optional] User defined method to solve residual equations, computing the outputs given the inputs. Define this method to implement a custom solver. Assigning a nonlinear solver will cause evaluate_residual_equations to run instead.

Example

.. code-block:: python

def solve_residual_equations(self, inputs, outputs):    a = inputs['a']    b = inputs['b']    c = inputs['c']    outputs['x'] = (-b + (b ** 2 - 4 * a * c) ** 0.5) / (2 * a)

apply_inverse_jacobian#

def apply_inverse_jacobian(d_outputs, d_residuals, mode)

[Optional] Solve linear system. Invoked when solving coupled linear system; i.e. when solving Newton system to update implicit state variables, and when computing total derivatives

Example

.. code-block:: python

# using self.inv_jac defined in `compute_derivatives` exampledef apply_inverse_jacobian( self, d_outputs, d_residuals, mode)    if mode == 'fwd':        d_outputs['x'] = self.inv_jac * d_residuals['x']    elif mode == 'rev':        d_residuals['x'] = self.inv_jac * d_outputs['x']

compute_jacvec_product#

def compute_jacvec_product(inputs, outputs, d_inputs, d_outputs, d_residuals, mode)

[Optional] Implement partial derivatives by computing a matrix-vector product.

Example

.. code-block:: python

def compute_jacvec_product(        self,        inputs,        outputs,        d_inputs,        d_outputs,        d_residuals,        mode,    ):        a = inputs['a']        b = inputs['b']        c = inputs['c']        x = outputs['x']        if mode == 'fwd':            if 'x' in d_residuals:                if 'x' in d_outputs:                    d_residuals['x'] += (2 * a * x + b) * d_outputs['x']                if 'a' in d_inputs:                    d_residuals['x'] += x ** 2 * d_inputs['a']                if 'b' in d_inputs:                    d_residuals['x'] += x * d_inputs['b']                if 'c' in d_inputs:                    d_residuals['x'] += d_inputs['c']        elif mode == 'rev':            if 'x' in d_residuals:                if 'x' in d_outputs:                    d_outputs['x'] += (2 * a * x + b) * d_residuals['x']                if 'a' in d_inputs:                    d_inputs['a'] += x ** 2 * d_residuals['x']                if 'b' in d_inputs:                    d_inputs['b'] += x * d_residuals['x']                if 'c' in d_inputs:                    d_inputs['c'] += d_residuals['x']

csdl.core.node

slice_to_tuple#

def slice_to_tuple(key: slice, size: int) -> tuple

Node Objects#

class Node()

The Node class is a base type for nodes in a Directed Acyclic Graph (DAG) that represents the computation to be performed during model evaluation.

__init__#

def __init__(*args, **kwargs)

__iadd__#

def __iadd__(other)

__iand__#

def __iand__(other)

__idiv__#

def __idiv__(other)

__ifloordiv__#

def __ifloordiv__(other)

__ilshift__#

def __ilshift__(other)

__imod__#

def __imod__(other)

__imul__#

def __imul__(other)

__ior__#

def __ior__(other)

__ipow__#

def __ipow__(other)

__irshift__#

def __irshift__(other)

__isub__#

def __isub__(other)

__ixor__#

def __ixor__(other)

add_fwd_edges#

def add_fwd_edges()

remove_fwd_edges#

def remove_fwd_edges()

Remove fwd edges so that we can update the graph. This is only used when exposing intermediate variables for a composite residual.

remove_dependencies#

def remove_dependencies()

Remove bwd edges so that we can update the graph. This is only used when exposing intermediate variables for a composite residual.

add_dependent_node#

def add_dependent_node(dependent)

remove_dependent_node#

def remove_dependent_node(dependent)

remove_dependency_node#

def remove_dependency_node(dependent)

register_nodes#

def register_nodes(nodes: dict)

Register all nodes in DAG.

Parameters

nodes: dict[Variable] Dictionary of nodes registered so far

incr_times_visited#

def incr_times_visited()

Increment number of times a node is visited during topological_sort. This is necessary for topological_sort to determine execution order for expressions.

get_dependency_index#

def get_dependency_index(candidate) -> Optional[int]

Get index of dependency in self.dependencies. Used for removing indirect dependencies that woud otherwise affect the cost of branches in the DAG, which would affect execution order, even with the sme constraints on execution order.

Parameters

candidate: Variable The candidate dependency node

Returns

Optional[int] If dependency is a dependency of self, then the index of dependency in self.dependencies is returned. Otherwise, None is returned.

remove_dependency_by_index#

def remove_dependency_by_index(index)

Remove dependency node, given its index. does nothing if index is out of range. See Variable.remove_dependency.

Parameters

index: int Index within self.dependencies where the node to be removed might be

remove_dependency_node#

def remove_dependency_node(candidate)

Remove dependency node. Does nothing if candidate is not a dependency. Used for removing indirect dependencies and preventing cycles from forming in DAG.

Parameters

candidate: Variable Node to remove from self.dependencies

get_dependent_index#

def get_dependent_index(candidate) -> Optional[int]

Get index of dependency in self.dependencies. Used for removing indirect dependencies that woud otherwise affect the cost of branches in the DAG, which would affect execution order, even with the sme constraints on execution order.

Parameters

candidate: Variable The candidate dependency node

Returns

Optional[int] If dependency is a dependency of self, then the index of dependency in self.dependencies is returned. Otherwise, None is returned.

_dedup_dependencies#

def _dedup_dependencies()

Remove duplicate dependencies. Used when adding a dependency.

remove_dependent_by_index#

def remove_dependent_by_index(index)

Remove dependency node, given its index. does nothing if index is out of range. See Variable.remove_dependency.

Parameters

index: int Index within self.dependencies where the node to be removed might be

remove_dependent_node#

def remove_dependent_node(candidate)

Remove dependency node. Does nothing if candidate is not a dependency. Used for removing indirect dependencies and preventing cycles from forming in DAG.

Parameters

candidate: Variable Node to remove from self.dependencies

print_dag#

def print_dag(depth=-1, indent='')

Print the graph starting at this node (debugging tool)

get_num_dependents#

def get_num_dependents()

csdl.core.variable

slice_to_tuple#

def slice_to_tuple(key: slice, size: int) -> tuple

Variable Objects#

class Variable(Node)

__init__#

def __init__(name, val=1.0, shape=(1, ), units=None, desc='', tags=None, shape_by_conn=False, copy_shape=None, distributed=None, *args, **kwargs, *, ,)

__pos__#

def __pos__()

__neg__#

def __neg__()

__add__#

def __add__(other)

__sub__#

def __sub__(other)

__mul__#

def __mul__(other)

__truediv__#

def __truediv__(other)

__pow__#

def __pow__(other)

__radd__#

def __radd__(other)

__rsub__#

def __rsub__(other)

__rmul__#

def __rmul__(other)

__rtruediv__#

def __rtruediv__(other)

__getitem__#

def __getitem__(key: Union[int, slice, Tuple[slice]])

add_dependency_node#

def add_dependency_node(dependency)

csdl.core.output

Output Objects#

class Output(Variable)

Base class for outputs; used to prevent circular imports

__init__#

def __init__(name, val=1.0, shape=(1, ), units=None, desc='', tags=None, shape_by_conn=False, copy_shape=None, distributed=None, res_units=None, lower=None, upper=None, ref=1.0, ref0=0.0, res_ref=1.0, op=None, *args, **kwargs, *, ,)

csdl.core.concatenation

Concatenation Objects#

class Concatenation(Output)

Class for creating an explicit output

__init__#

def __init__(name, val=1.0, shape: Tuple[int] = (1, ), units=None, desc='', tags=None, shape_by_conn=False, copy_shape=None, res_units=None, lower=None, upper=None, ref=1.0, ref0=0.0, res_ref=1.0, *args, **kwargs, *, ,)

Initialize explicit output

Parameters

name: str Name of variable to compute explicitly shape: Tuple[int] Shape of variable to compute explicitly val: Number or ndarray Initial value of variable to compute explicitly

__setitem__#

def __setitem__(key: Union[int, slice, Tuple[slice]], var: Variable)

csdl.core.operation

Operation Objects#

class Operation(Node)

__init__#

def __init__(*args, **kwargs, *, ,)

add_dependency_node#

def add_dependency_node(dependency)

csdl.core.standard_operation

StandardOperation Objects#

class StandardOperation(Operation)

__init__#

def __init__(*args, **kwargs)

define_compute_strings#

def define_compute_strings()

csdl.core.custom_operation

CustomOperation Objects#

class CustomOperation(Operation)

__init__#

def __init__(*args, **kwargs)

initialize#

def initialize()

User defined method to declare parameter values. Parameters are compile time constants (neither inputs nor outputs to the model) and cannot be updated at runtime. Parameters are intended to make a CustomOperation subclass definition generic, and therefore reusable. The example below shows how a CustomOperation subclass definition uses parameters and how the user can set parameters when constructing the example CustomOperation subclass. Note that the user never instantiates nor inherits directly from the CustomOperation base class.

Example

# in this example, we inherit from ExplicitOperation, but# the user can also inherit from ImplicitOperationclass Example(ExplicitOperation):    def initialize(self):        self.parameters.declare('in_name', types=str)        self.parameters.declare('out_name', types=str)
    def define(self):        # use parameters declared in ``initialize``        in_name = self.parameters['in_name']        out_name = self.parameters['out_name']
        self.add_input(in_name)        self.add_output(out_name)        self.declare_derivatives(out_name, in_name)
    # define run time behavior by defining other methods...
# compile using Simulator imported from back end...sim = Simulator(    Example(        in_name='x',        out_name='y',    ),)

define#

def define()

User defined method to define custom operation

Example

.. code-block:: python

def define(self):    self.add_input('Cl')    self.add_input('Cd')    self.add_input('rho')    self.add_input('V')    self.add_input('S')    self.add_output('L')    self.add_output('D')
    # declare derivatives of all outputs wrt all inputs    self.declare_derivatives('*', '*'))

add_input#

def add_input(name, val=1.0, shape=(1, ), src_indices=None, flat_src_indices=None, units=None, desc='', tags=None, shape_by_conn=False, copy_shape=None)

Add an input to this operation.

Example

class Example(ExplicitOperation):    def define(self):        self.add_input('Cl')        self.add_input('Cd')        self.add_input('rho')        self.add_input('V')        self.add_input('S')        self.add_output('L')        self.add_output('D')
    # ...
class Example(ImplicitOperation):    def define(self):        self.add_input('a', val=1.)        self.add_input('b', val=-4.)        self.add_input('c', val=3.)        self.add_output('x', val=0.)
    # ...

add_output#

def add_output(name, val=1.0, shape=(1, ), units=None, res_units=None, desc='', lower=None, upper=None, ref=1.0, ref0=0.0, res_ref=1.0, tags=None, shape_by_conn=False, copy_shape=None, distributed=None)

Add an output to this operation.

Example

class Example(ExplicitOperation):    def define(self):        self.add_input('Cl')        self.add_input('Cd')        self.add_input('rho')        self.add_input('V')        self.add_input('S')        self.add_output('L')        self.add_output('D')
    # ...
class Example(ImplicitOperation):    def define(self):        self.add_input('a', val=1.)        self.add_input('b', val=-4.)        self.add_input('c', val=3.)        self.add_output('x', val=0.)
    # ...

declare_derivatives#

def declare_derivatives(of, wrt, dependent=True, rows=None, cols=None, val=None, method='exact', step=None, form=None, step_calc=None)

Declare partial derivatives of each output with respect to each input (ExplicitOperation) or each residual associated with an output with respect to the input/output (ImplicitOperation).

class Example(ExplicitOperation):    def define(self):        self.add_input('Cl')        self.add_input('Cd')        self.add_input('rho')        self.add_input('V')        self.add_input('S')        self.add_output('L')        self.add_output('D')
        # declare derivatives of all outputs wrt all inputs        self.declare_derivatives('*', '*')
    # ...
class Example(ImplicitOperation):    def define(self):        self.add_input('a', val=1.)        self.add_input('b', val=-4.)        self.add_input('c', val=3.)        self.add_output('x', val=0.)        # declare derivative of residual associated with x        # wrt x        self.declare_derivatives('x', 'x')        # declare derivative of residual associated with x        # wrt a, b, c        self.declare_derivatives('x', ['a','b','c'])
        self.linear_solver = ScipyKrylov()        self.nonlinear_solver = NewtonSolver(solve_subsystems=False)
    # ...

csdl.core.subgraph

Subgraph Objects#

class Subgraph(Node)

Class for declaring an input variable

__init__#

def __init__(name: str, submodel, *args, *, promotes=None, min_procs=1, max_procs=None, proc_weight=1.0, **kwargs, ,)

add_dependency_node#

def add_dependency_node(dependency)