Developer API
csdl.core.model
#
ImplicitOperationFactory Objectsclass ImplicitOperationFactory(object)
#
__init__def __init__(parent, model)
#
declare_statedef 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_tabledef build_symbol_table(symbol_table, node)
#
_run_front_end_and_middle_enddef _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 Objectsclass _CompilerFrontEndMiddleEnd(type)
#
__new__def __new__(cls, name, bases, attr)
#
Model Objectsclass Model(, metaclass=_CompilerFrontEndMiddleEnd)
#
__init__def __init__(**kwargs)
#
optimize_irdef optimize_ir(flag: bool = True)
#
initializedef 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, ), )
#
definedef 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
#
_redefinedef _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_vardef 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_objectivedef 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_variabledef 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_constraintdef 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.
#
connectdef connect(a: str, b: str)
#
declare_variabledef 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_inputdef 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_outputdef 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_outputdef 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)
#
adddef 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_searchdef _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
for , given some value of .
CSDL solves by defining a residual and
updating until 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 instates
must also match the order of the names of the residuals associated with each state inresiduals
.
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 tostates
andexpose
, and are returned in the same order in which they are declared. For example, ifstates=['a', 'b', 'c']
andexpose=['d', 'e', 'f']
, then the outputsa, b, c, d, e, f
ina, 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) frommodel
in thisModel
. Unused outputs will be ignored, soa, b, c = self.implcit_output(...)
will make the variables declared inexpose
available for recording/analysis and promotion/connection, but they will be unused by thisModel
. Note that these variables are already registered as outputs in thisModel
, so there is no need to callModel.register_output
for any of these variables.
#
_implicit_operationdef _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
for , given some value of .
CSDL solves by defining a residual and
updating until 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.
#
_somethingdef _something(model, arguments, states, residuals, expose: List[str] = [])
#
_return_implicit_outputsdef _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_operationdef 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_sparsitydef visualize_sparsity()
Visualize the sparsity pattern of jacobian for this model
#
visualize_graphdef visualize_graph()
#
add_diag_implicitdef add_diag_implicit(A, variables, implicit_outputs, indices=dict(), implicit_nodes=dict(), p=0, indent='')
#
add_off_diag_implicitdef add_off_diag_implicit(A, indices, implicit_nodes)
#
add_diagdef add_diag(A, nodes, indices=dict(), implicit_nodes=dict(), p=0, indent='')
#
add_off_diagdef add_off_diag(A, model, indices)
csdl.core.simulator_base
#
_ReprClass Objectsclass _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 Objectsclass 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
#
rundef 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_derivativesdef 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_hessiandef compute_exact_hessian()
Method to compute exact Hessian
#
check_partialsdef 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_partialsdef 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_implementationdef visualize_implementation()
A method for the back end to provide its own visualization of the model.
#
get_design_variable_metadatadef get_design_variable_metadata() -> dict
Method to get design variable metadata that an optimizer needs to define an optimization problem
Returns
`dict`
#
get_constraints_metadatadef get_constraints_metadata() -> OrderedDict
Method to get constraint metadata that an optimizer needs to define an optimization problem
Returns
`OrderedDict`
#
update_design_variablesdef update_design_variables(x: np.ndarray, input_format='array')
Method for external optimizer to update design variable values
#
design_variablesdef design_variables(return_format='array') -> Union[OrderedDict, np.ndarray]
Method to provide optimizer with design variables Returns
`Union[OrderedDict, np.ndarray]`
#
objectivedef objective() -> float
Method to provide optimizer with objective
#
constraintsdef constraints(return_format='array') -> Union[OrderedDict, np.ndarray]
Method to provide optimizer with constraints
Returns
`Union[OrderedDict, np.ndarray]`
#
implicit_outputsdef implicit_outputs()
Method to provide optimizer with implicit_outputs
#
residualsdef residuals() -> Union[OrderedDict, np.ndarray]
Method to provide optimizer with residuals
#
objective_gradientdef 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_jacobiandef 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_jacobiandef 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 Objectsclass CustomExplicitOperation(CustomOperation)
#
computedef 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_derivativesdef 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_productdef 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 Objectsclass CustomImplicitOperation(CustomOperation)
#
__init__def __init__(*args, **kwargs)
#
evaluate_residualsdef 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_derivativesdef 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_equationsdef 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_jacobiandef 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_productdef 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_tupledef slice_to_tuple(key: slice, size: int) -> tuple
#
Node Objectsclass 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_edgesdef add_fwd_edges()
#
remove_fwd_edgesdef 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_dependenciesdef 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_nodedef add_dependent_node(dependent)
#
remove_dependent_nodedef remove_dependent_node(dependent)
#
remove_dependency_nodedef remove_dependency_node(dependent)
#
register_nodesdef register_nodes(nodes: dict)
Register all nodes in DAG.
Parameters
nodes: dict[Variable] Dictionary of nodes registered so far
#
incr_times_visiteddef 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_indexdef 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_indexdef 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_nodedef 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_indexdef 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_dependenciesdef _dedup_dependencies()
Remove duplicate dependencies. Used when adding a dependency.
#
remove_dependent_by_indexdef 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_nodedef 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_dagdef print_dag(depth=-1, indent='')
Print the graph starting at this node (debugging tool)
#
get_num_dependentsdef get_num_dependents()
csdl.core.variable
#
slice_to_tupledef slice_to_tuple(key: slice, size: int) -> tuple
#
Variable Objectsclass 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_nodedef add_dependency_node(dependency)
csdl.core.output
#
Output Objectsclass 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 Objectsclass 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 Objectsclass Operation(Node)
#
__init__def __init__(*args, **kwargs, *, ,)
#
add_dependency_nodedef add_dependency_node(dependency)
csdl.core.standard_operation
#
StandardOperation Objectsclass StandardOperation(Operation)
#
__init__def __init__(*args, **kwargs)
#
define_compute_stringsdef define_compute_strings()
csdl.core.custom_operation
#
CustomOperation Objectsclass CustomOperation(Operation)
#
__init__def __init__(*args, **kwargs)
#
initializedef 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', ),)
#
definedef 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_inputdef 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_outputdef 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_derivativesdef 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 Objectsclass 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_nodedef add_dependency_node(dependency)