Primary Class Reference

This page outlines the three primary classes for Flume: Analysis, State, and System.

class flume.base_classes.analysis.Analysis(obj_name: str, sub_analyses: list = [], **kwargs)

This is a base class for all derived analysis classes that establishes a set of common methods. For the variables and outputs that are stored as attributes of the class, data is stored in dictionaries with key-value pairs structured as “variable/output name” : State object that describes the variable/output.

__init__(obj_name: str, sub_analyses: list = [], **kwargs)

Base class construction for an instance of an Analysis object within the Flume framework.

Parameters:
  • obj_name (str) – Name for the analysis object, which should be unique among all Analysis objects that are included for a System

  • sub_analyses (list) – A list of sub-analyses for the object, which will either be empty or contain other instances of objects that inherit from the Analysis base class

Keyword Arguments:

class (Here, **kwargs are keyword arguments that correspond to parameters that should be set for Analysis classes. There are no keyword arguments/parameters by default, but the user can alter this by creating the self.default_parameters dictionary in their class that inherits from the Analysis base)

analyze(mode='real', debug_print=False)

Performs the analysis procedure for the object after combining the objects into a list that contains the stack. For each analysis in the stack, connections are established between sub-analyses and primary-analyses and then the private _analyze method is called.

analyze_adjoint(debug_print=False)

Performs the adjoint analysis for the object and propagates any computations back through other sub-analyses included in the stack. Internally, this is done by reversing through the stack performing the adjoint analysis for each individual object.

declare_design_vars(variables: list)

Declare design variables for the analysis object. This could be all of the variables for the object or a subset based on the user input to the method.

Parameters:

variables (list) – A list of strings which correspond to the variables that are to be included as design variables for the analysis object. This list is stored internally as an attribute and specifies which variables are included in adjoint tests.

get_global_name(local_name: str) → str

Gets the global name for an input local name. This function works for all parameters, variables, and outputs.

Parameters:

local_name (str) – A string that is the local name for a given parameter, variable, or output of the object.

Returns:

global_name – A string that is the global name for a given parameter, variable, or output of the object.

Return type:

str

get_output_metadata(outputs: list = ['all'], display_info=False) → dict

Gets the metadata associated with the outputs specified in the outputs list.

Parameters:

outputs (list) – A list of strings that specifies the local output names that are to be accessed. Default is “all”, which returns the metadata for all outputs for the object.

Returns:

  • out_meta (dict) – A dictionary of dictionaries for the specified outputs. Each sub-dictionary contains key-value pairs for the following information: variable type, shape (if applicable), and description.

  • display_info (bool) – Boolean value that dictates whether variable metadata should be displayed when this method is called. Default is False.

get_output_values(outputs: list = ['all'], display_data=False) → dict

Gets the values for the specified outputs.

Parameters:

outputs (list) – A list of strings that specifies the local output names that are to be returned. Default is “all”, which returns all of the outputs for the object.

Returns:

  • output_values (dict) – A dictionary that contains key-value pairs for the desired outputs based on the input to the function.

  • display_data (bool) – Boolean value that dictates whether output values should be displayed when this method is called. Default is False.

get_parameter_values(params: list = ['all'], display_data=False) → dict

Gets the values for the parameters specified in the parameters input list.

Parameters:

params (list) – A list of strings that specifies the local parameter names that are to be returned. Default is “all”, which returns all of the parameters for the object.

Returns:

  • param_values (dict) – A dictionary that contains key-value pairs for the desired parameters based on the input to the function.

  • display_data (bool) – Boolean value that dictates whether parameter values should be displayed when this method is called. Default is False.

get_var_derivs(variables=['all']) → dict

Gets the derivative values for the variables specified in the variables input list.

Parameters:

variables (list) – A list of strings that specifies the local variable names that are to be returned. Default is “all”, which returns all of the variables for the object.

Returns:

var_derivs – A dictionary that contains key-value pairs for the desired variable derivatives based on the input to the function.

Return type:

dict

get_var_metadata(variables: list = ['all'], display_info=False) → dict

Gets the metadata associated with the variables specified in the variables input list.

Parameters:

variables (list) – A list of strings that specifies the local variable names that are to be accessed. Default is “all”, which returns the metadata for all variables for the object.

Returns:

  • var_meta (dict) – A dictionary of dictionaries for the specified variables in the input. Each sub-dictionary contains key-value pairs for the following information: variable type, shape (if applicable), and description.

  • display_info (bool) – Boolean value that dictates whether variable metadata should be displayed when this method is called. Default is False.

get_var_values(variables=['all'], display_data=False) → dict

Gets the values for the variables specified in the variables input list.

Parameters:

variables (list) – A list of strings that specifies the local variable names that are to be returned. Default is “all”, which returns all of the variables for the object.

Returns:

  • var_values (dict) – A dictionary that contains key-value pairs for the desired variables based on the input to the function.

  • display_data (bool) – Boolean value that dictates whether variable values should be displayed when this method is called. Default is False.

set_var_values(variables: dict)

Sets the values for the varaibles based on the entries contained in the variables dictionary

Parameters:

variables (dict) – A dictionary that is structued with key-value pairs, where the key is the local name of the variable and the value is the numerical value to set for the variable.

Return type:

None, but internally State objects for the specified variables are updated with the provided values.

test_combined_adjoint(print_res=True, debug_print=False, method='cs', defined_vars={}, dh_cs=1e-30, dh_fd=1e-06)

Tests the adjoint implementation for an analysis object and accounts for any sub-analyses within the stack.

Parameters:
  • debug_print (bool) – Boolean value that specifies whether debug print statements should be displayed

  • method (str) – Either ‘cs’ or ‘fd’, which specifies that the method to check against the adjoint implementation is complex-step or finite-difference, respectively

  • defined_vars (dictionary) – A dictionary where the keys correspond to the global variable names and the values are the numeric values that the variables should have. For example, if the user wants to set a variable ‘x’ for an analysis object ‘analysis’ to be value 1.0, defined_vars should be given as defined_vars = {‘analysis.x’: 1.0}.

test_isolated_adjoint(print_res=True, debug_print=False, method='cs', defined_vars={}, dh_fd=1e-06, dh_cs=1e-30)

Tests the adjoint implementation for an analysis object (ignores any sub-analyses for the isolated case). Currently, only the complex-step method is implemented for this test, so calculations must be complex-safe.

Parameters:

defined_vars (dictionary) – Dictionary that specifies whether any variables that have defined values for the adjoint test. This is nominally empty, but is sometimes necessary for variables that have strict bounds.

Return type:

None, but displays results of adjoint analysis test

class flume.base_classes.state.State(value, desc: str, deriv=None, source=None)

This is a class to use for establishing a structure for variables and outputs of analysis classes.

__init__(value, desc: str, deriv=None, source=None)

Base class that is used to wrap variables and outputs within the Flume framework.

Parameters:
  • value (float or np.ndarray) – Numeric value for the State

  • desc (str) – String that describes the State

  • deriv (float or np.ndarray) – Value for the State’s derivative. This is None by default, and the user does not need to provide a numeric value when constructing the object

  • source (class instance) – Object where the State data is sourced from. When creating states, this should be set to “self”, otherwise the framework will raise an error

data_type

The data type for the value of the State

Type:

type

shape

This is only created if the value for the State is a NumPy array, and it corresponds to the shape for the value

Type:

tuple

property deriv

Defines the derivative property, accessing a specific key in the dictionary for the current context (sweep and, if set, writer).

ensure_sweep_slot(sweep_id)

Method used to serially ensure that all keys exist for all of the necessary parallel paths, as the dictionary key insertion during execution is not thread-safe.

get_deriv(sweep_id=None)

Helper method that gets the derivative value for the given sweep ID (which is used to account for which quantity of interest is being tracked)

prepare_writer_slot(sweep_id, writer_id)

Serially create (and zero) the private per-writer contribution buffer for the (sweep_id, writer_id) pair, prior to the parallel adjoint. Pre-creating these keys is required because dictionary key insertion during parallel execution is not thread-safe; during the parallel phase only the values of existing keys are mutated.

reduce_seed(sweep_id, reader_id)

Compute the incoming adjoint (seed) for this State in the given sweep and placeit in the reader’s private buffer so that the reader’s _analyze_adjoint observesthe correct value.

The seed is the canonical seed for this sweep (set by _add_output_seed for sink outputs, zero otherwise) plus the sum of every consumer’s contribution buffer for this sweep. This is called from the producer of the State, which (by the transpose-graph readiness) runs only after all consumers have finished, so every consumer buffer is final.

Parameters:
  • sweep_id – The sweep (quantity of interest) currently being processed.

  • reader_id – The id() of the node that will read this seed (the State’s producer).

reduce_to_canonical(sweep_id)

Sum all per-writer contribution buffers for the given sweep into the canonical sweep_id slot. Used after the parallel adjoint completes so that get_deriv (which reads the canonical slot) returns the total accumulated derivative – e.g. for design-variable gradient extraction.

set_deriv_value(deriv_val)

Method to set the derivative value in the derivative object, accounting for the ContextVar, if necessary. Utilizes the setter method for the deriv property.

flume.base_classes.state.sweep_context(sweep_id)

Context manager for the System, which uses the value of the sweep_id input to perform the adjoint analysis.

class flume.base_classes.system.System(sys_name: str, top_level_analysis_list: List[Analysis], log_name: str = 'flume.log', log_prefix: str = '.', parallel_execution: bool = False, parallel_max_workers: int = 4, track_node_timing: bool = False)

This class is used to wrap multiple Analysis objects into a system, which can then be utilized to perform optimization using one of Flume’s optimizer interfaces.

__init__(sys_name: str, top_level_analysis_list: List[Analysis], log_name: str = 'flume.log', log_prefix: str = '.', parallel_execution: bool = False, parallel_max_workers: int = 4, track_node_timing: bool = False)

Defines a class that wraps multiple analysis objects into a single system, which can then be utilized to perform optimization with one of Flume’s optimizer interfaces after declaring design varaibles, an objective function, and (optionally) constraints.

Parameters:
  • sys_name (str) – Name that is assigned to the System

  • top_level_analysis_list (list) – A list of instances of Analysis objects that will be utilized within the optimization problem. Here, the objects that should be provided are the analyses that define the objective function and any constraint functions so that these can be declared for the optimization formulation. Other Analysis classes, such as those used as sub-analyses, do not need to be provided here, as they should be provided when creating the objects in the top-level analysis list

  • log_name (str) – String that defines the name to use for the log file, defaults to ‘flume.log’

  • log_prefix (str) – String that defines the output directory where the log file and other files are saved, defaults to the current directory ‘.’

  • parallel_execution (bool) – Boolean operator that specifies whether the DAG should be executed in parallel for the forward and adjoint analyses. Defaults to False.

  • parallel_max_workers (int) – Only applied when parallel_execution is True. Spawns this many threads for performing the forward/adjoint analyses in parallel.

  • track_node_timing (bool) – Boolean value that specifies whether the profile.log file should track the execution time for the forward and adjoint analyses for each node in the DAG.

assemble_full_analysis_list()

Assembles the full list of analyses that comprise the overall system architecture.

build_dag()

Method to construct the directed acyclic graph for the System. Utilizes the nodes defined as the top-level Analysis objects and their sub-analyses to construct the DAG strucutre. Creates attributes which define the following:

self.dag_nodes : a set for all unique nodes in the DAG self.dag_dependents : a dictionary which specifies the children/dependents for each node in the DAG self.dag_remaining : a dictionary that specifies the number of remaining nodes that need to be analzed before a given node can be analyzed (i.e. number of unanalyzed ancestors for each node) self.dag_sink_ancestors : a dictionary that defines the reverse mapping, where each node is mapped to its ancestors (opposite of self.dag_dependents)

declare_constraints(global_con_name: dict)

Sets the constraints for the optimization problem according to the provided global output names.

Parameters:

global_con_name_dict (dict) –

This is a dictionary of dictionaries. The keys correspond to the global output names for the constraints. The inner dictionary specifies additional information about the structure of the constriant, including the following:

  • ’rhs’ (float) - specifies the right hand side of the constraint equation. Internally, the optimizer interfaces will use this to convert the constraint to an equivalent form that normalizes it, If the ‘rhs’ value is 0.0, no scaling is applied

  • ’direction’ (str) - string that is either ‘geq’ (>=), ‘leq’ (<=), or ‘both’ (=). Defaults to ‘geq’ in the event that a direction is not provided.

Example

Here, the constraints are defined as follows:

x <= 1.0 y >= 1.0 z = 2.0

Thus, the argument here is given as: global_con_name = {

“block1.x”:{“direction”:”leq”, “rhs”:1.0}, “block2.y”:{“rhs”:1.0} “block3.z”:{“direction”: “both”, “rhs”: 2.0} }

declare_design_vars(global_var_name: dict)

Sets the design variables for the system according to the provided global variable names.

Parameters:

global_var_name (dict) – This is a dictionary of dictionaries. Keys for the first dictionary correspond to the global variable names that should be added to the set of design variables, and the values contain information about the variable bounds. If the inner dictionary is empty, then no bounds are provided. Otherwise, the values for the variables lower bound ‘lb’ and upper bound ‘ub’ will be added, if included.

Example

Here, the bounds are defined as follows:

1.0 <= x <= 2.0 y has no bounds 0.0 <= z

Thus, the argument here is: global_var_name = {“block1.x”:{“lb”:1.0, “lb”:2.0}, “block2.y”:{}, “block3.z”:{“lb”:0.0}}

declare_foi(global_foi_name: list)

Sets the functions of interest that are to be tracked by the logger at each iteration. Here, the names must be provided according to their global names. If already declared, the objective and constraints are added by default, but other outputs can be included.

declare_objective(global_obj_name, obj_scale=1.0)

Sets the objective function for the optimization problem according to the provided global output name. This output should be associated with one of the top-level analyses for the system (i.e. included in the top_level_analysis_list).

Parameters:
  • global_obj_name (str) – A string that specifies the global name for the value that is to be used as the objective function (global name meaning ‘object_name.local_output_name’)

  • obj_scale (float) – Float value that is multiplied by the value of the objective function, which should scale the objective function value to O(1). This is used by the optimizer interfaces internally to scale the objective.

execute(mode: str = 'real', debug_print: bool = False)

Executes all top-level Analysis objects for the System. Operates in serial or in parallel, depending on the input parameter.

execute_adjoint(debug_print: bool = False)

Executes the adjoint analysis for the System. Operates in serial or in parallel, depending on the boolean attribute for parallel execution. If executing in parallel, makes use of ThreadPoolExecutor to sweep over adjoint analyses for each output of interest (i.e. objective or constraints) in parallel, known as a sweep in code. Within a given sweep, also uses ancestor dictionary to execute adjoint analyses in parallel as soon as all of a nodes dependents have completed their respective adjoint analyses. Thus, leverages two forms of parallelism here. Note that locks are used for the _analyze_adjoint method to prevent instances when two sweeps attempt to call this method at the same time.

finalize_profile_log()

Writes a final summary line to profile.log recording the total wall-clock run time for the entire optimization. The run start is captured lazily on the first call to profile_iteration(), so this should be called once after the optimization loop completes.

If profile_iteration() was never called (e.g. no iterations ran), the total run time is reported as NaN.

graph_network(filename: str = None, output_directory: str = None, interactive: bool = False, format: str = 'pdf', consolidated_graph: bool = False)

Construct the visualization of the network associated with the Flume system using graphviz.

Parameters:
  • filename (str) – Name to use for the file that is created

  • output_directory (str) – String that defines the directory where the file should be saved

  • interactive (bool) – Boolean value that indicates whether the graph should be output in interactive mode. This is an experimental feature at the moment

log_information(iter_number)

Helper function that is used to log the values for the objective function, constraints, and other functions of interest at each iteration. Internally, this will update the log file for the System with this information at every iteration.

Parameters:

iter_number (int) – Current iteration number

profile_iteration(iter_number)

Helper function that is used to display the time taken for each analyze and analyze_adjoint method at the current iteration. Internally, this updates a profile log file that stores the timing information for the System at each iteration.

Parameters:

iter_number (int) – Current iteration number

reset_analysis_flags()

Resets all of the analysis flags for all analyses within the system to be False. This is done when variable values are updated, as all systems must be analyzed again to propagate changes in design variable values.