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) -> CallableRun 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 yadd_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) -> DeclaredVariableDeclare 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) -> InputCreate 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) -> ConcatenationCreate 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] = bParameters
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) -> OutputRegister 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 CSDLvar: Output
Variable that defines outputReturns
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
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 instatesmust 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
Modelobject 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
modelthat 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 tostatesandexpose, 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, fina, 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) frommodelin thisModel. Unused outputs will be ignored, soa, b, c = self.implcit_output(...)will make the variables declared inexposeavailable 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_outputfor 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
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 residualslinear_solver: LinearSolver
The linear solver to use to solve the linear systemexpose: 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.ndarrayMethod 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() -> dictMethod to get design variable metadata that an optimizer needs to define an optimization problem
Returns
`dict`get_constraints_metadata#
def get_constraints_metadata() -> OrderedDictMethod 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() -> floatMethod 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']**2compute_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 + ccompute_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) -> tupleNode 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) -> tupleVariable 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)