def _check_cycles(group, infos=None): """ Report any cycles to the logger. Parameters ---------- group : <Group> The Group being checked for dataflow issues infos : list List to collect informational messages. Returns ------- list List of cycles, with subsystem names sorted in execution order. """ graph = group.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) cycles = [sorted(s, key=lambda n: group._subsystems_allprocs[n].index) for s in sccs if len(s) > 1] if cycles and infos is not None: infos.append(" Group '%s' has the following cycles: %s\n" % (group.pathname, cycles)) return cycles
def _check_dataflow(group, infos, warnings): """ Report any cycles and out of order Systems to the logger. Parameters ---------- group : <Group> The Group being checked for dataflow issues infos : list List to collect informational messages. warnings : list List to collect warning messages. """ graph = group.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) sub2i = {sub.name: i for i, sub in enumerate(group._subsystems_allprocs)} cycles = [sorted(s, key=lambda n: sub2i[n]) for s in sccs if len(s) > 1] cycle_idxs = {} if cycles: infos.append(" Group '%s' has the following cycles: %s\n" % (group.pathname, cycles)) for i, cycle in enumerate(cycles): # keep track of cycles so we can detect when a system in # one cycle is out of order with a system in a different cycle. for s in cycle: if group.pathname: s = '.'.join((group.pathname, s)) cycle_idxs[s] = i ubcs = _get_out_of_order_subs(group, group._conn_global_abs_in2out) for tgt_system, src_systems in sorted(ubcs.items()): keep_srcs = [] for src_system in src_systems: if not (src_system in cycle_idxs and tgt_system in cycle_idxs and cycle_idxs[tgt_system] == cycle_idxs[src_system]): keep_srcs.append(src_system) if keep_srcs: warnings.append(" System '%s' executes out-of-order with " "respect to its source systems %s\n" % (tgt_system, sorted(keep_srcs)))
def _check_dataflow(group, infos, warnings): """ Report any cycles and out of order Systems to the logger. Parameters ---------- group : <Group> The Group being checked for dataflow issues infos : list List to collect informational messages. warnings : list List to collect warning messages. """ graph = group.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) sub2i = {sub.name: i for i, sub in enumerate(group._subsystems_allprocs)} cycles = [sorted(s, key=lambda n: sub2i[n]) for s in sccs if len(s) > 1] cycle_idxs = {} if cycles: infos.append(" Group '%s' has the following cycles: %s\n" % (group.pathname, cycles)) for i, cycle in enumerate(cycles): # keep track of cycles so we can detect when a system in # one cycle is out of order with a system in a different cycle. for s in cycle: if group.pathname: s = '.'.join((group.pathname, s)) cycle_idxs[s] = i ubcs = _get_out_of_order_subs(group, group._conn_global_abs_in2out) for tgt_system, src_systems in sorted(ubcs.items()): keep_srcs = [] for src_system in src_systems: if not (src_system in cycle_idxs and tgt_system in cycle_idxs and cycle_idxs[tgt_system] == cycle_idxs[src_system]): keep_srcs.append(src_system) if keep_srcs: warnings.append(" System '%s' executes out-of-order with " "respect to its source systems %s\n" % (tgt_system, sorted(keep_srcs)))
def _check_dataflow(group, logger): """ Report any cycles and out of order Systems to the logger. Parameters ---------- group : <Group> The Group being checked for dataflow issues. logger : object The object that manages logging output. """ graph = group.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) cycles = [sorted(s) for s in sccs if len(s) > 1] cycle_idxs = {} if cycles: logger.warning("Group '%s' has the following cycles: %s" % (group.pathname, cycles)) for i, cycle in enumerate(cycles): # keep track of cycles so we can detect when a system in # one cycle is out of order with a system in a different cycle. for s in cycle: cycle_idxs[s] = i ubcs = _get_out_of_order_subs(group, group._conn_global_abs_in2out) for tgt_system, src_systems in sorted(ubcs.items()): keep_srcs = [] for src_system in src_systems: if not (src_system in cycle_idxs and tgt_system in cycle_idxs and cycle_idxs[tgt_system] == cycle_idxs[src_system]): keep_srcs.append(src_system) if keep_srcs: logger.warning("System '%s' executes out-of-order with " "respect to its source systems %s" % (tgt_system, sorted(keep_srcs)))
def _check_solvers(problem, logger): """ Search over all solvers and raise an error for unsupported configurations. Report any implicit component that does not implement solve_nonlinear and solve_linear or have an iterative nonlinear and linear solver upstream of it. Report any cycles that do not have an iterative nonlinear solver and either an iterative linear solver or a DirectSolver upstream of it. Parameters ---------- problem : <Problem> The problem being checked. logger : object The object that manages logging output. """ iter_nl_depth = iter_ln_depth = np.inf for sys in problem.model.system_iter(include_self=True, recurse=True): path = sys.pathname depth = 0 if path == '' else len(path.split('.')) # if this system is below both a nonlinear and linear solver, then skip checks if (depth > iter_nl_depth) and (depth > iter_ln_depth): continue # determine if this system is a group and has cycles if isinstance(sys, Group): graph = sys.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) allsubs = sys._subsystems_allprocs has_cycles = [sorted(s, key=lambda n: allsubs[n].index) for s in sccs if len(s) > 1] else: has_cycles = [] # determine if this system has states (is an implicit component) has_states = isinstance(sys, ImplicitComponent) # determine if this system has iterative solvers or implements the solve methods # for handling cycles and implicit components if depth > iter_nl_depth: is_iter_nl = True else: is_iter_nl = ( (sys.nonlinear_solver and 'maxiter' in sys.nonlinear_solver.options) or (has_states and overrides_method('solve_nonlinear', sys, ImplicitComponent)) ) iter_nl_depth = depth if is_iter_nl else np.inf if depth > iter_ln_depth: is_iter_ln = True else: is_iter_ln = ( (sys.linear_solver and ('maxiter' in sys.linear_solver.options or isinstance(sys.linear_solver, DirectSolver))) or (has_states and overrides_method('solve_linear', sys, ImplicitComponent)) ) iter_ln_depth = depth if is_iter_ln else np.inf # if there are cycles, then check for iterative nonlinear and linear solvers if has_cycles: if not is_iter_nl: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "nonlinear solver." % (path, has_cycles)) logger.warning(msg) if not is_iter_ln: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "linear solver." % (path, has_cycles)) logger.warning(msg) # if there are implicit components, check for iterative solvers or the appropriate # solve methods if has_states: if not is_iter_nl: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative nonlinear solver and does not implement 'solve_nonlinear'." % (sys.__class__.__name__, path)) logger.warning(msg) if not is_iter_ln: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative linear solver and does not implement 'solve_linear'." % (sys.__class__.__name__, path)) logger.warning(msg)
def _check_solvers(problem, logger): """ Search over all solvers and raise an error for unsupported configurations. Report any implicit component that does not implement solve_nonlinear and solve_linear or have an iterative nonlinear and linear solver upstream of it. Report any cycles that do not have an iterative nonlinear solver and either an iterative linear solver or a DirectSolver upstream of it. Parameters ---------- problem : <Problem> The problem being checked. logger : object The object that manages logging output. """ iter_nl_depth = iter_ln_depth = np.inf for sys in problem.model.system_iter(include_self=True, recurse=True): path = sys.pathname depth = 0 if path == '' else len(path.split('.')) # if this system is below both a nonlinear and linear solver, then skip checks if (depth > iter_nl_depth) and (depth > iter_ln_depth): continue # determine if this system is a group and has cycles if isinstance(sys, Group): graph = sys.compute_sys_graph(comps_only=False) sccs = get_sccs_topo(graph) sub2i = {sub.name: i for i, sub in enumerate(sys._subsystems_allprocs)} has_cycles = [sorted(s, key=lambda n: sub2i[n]) for s in sccs if len(s) > 1] else: has_cycles = [] # determine if this system has states (is an implicit component) has_states = isinstance(sys, ImplicitComponent) # determine if this system has iterative solvers or implements the solve methods # for handling cycles and implicit components if depth > iter_nl_depth: is_iter_nl = True else: is_iter_nl = ( (sys.nonlinear_solver and 'maxiter' in sys.nonlinear_solver.options) or (has_states and overrides_method('solve_nonlinear', sys, ImplicitComponent)) ) iter_nl_depth = depth if is_iter_nl else np.inf if depth > iter_ln_depth: is_iter_ln = True else: is_iter_ln = ( (sys.linear_solver and ('maxiter' in sys.linear_solver.options or isinstance(sys.linear_solver, DirectSolver))) or (has_states and overrides_method('solve_linear', sys, ImplicitComponent)) ) iter_ln_depth = depth if is_iter_ln else np.inf # if there are cycles, then check for iterative nonlinear and linear solvers if has_cycles: if not is_iter_nl: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "nonlinear solver." % (path, has_cycles)) logger.warning(msg) if not is_iter_ln: msg = ("Group '%s' contains cycles %s, but does not have an iterative " "linear solver." % (path, has_cycles)) logger.warning(msg) # if there are implicit components, check for iterative solvers or the appropriate # solve methods if has_states: if not is_iter_nl: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative nonlinear solver and does not implement 'solve_nonlinear'." % (sys.__class__.__name__, path)) logger.warning(msg) if not is_iter_ln: msg = ("%s '%s' contains implicit variables, but does not have an " "iterative linear solver and does not implement 'solve_linear'." % (sys.__class__.__name__, path)) logger.warning(msg)